removed some stdlib dependencies; license; bug fixes
This commit is contained in:
parent
e25b69bd44
commit
f8f441648d
7
LICENSE.txt
Executable file
7
LICENSE.txt
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
Copyright © 2022 Aaron Manning
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
README.md
Normal file → Executable file
27
README.md
Normal file → Executable file
@ -6,7 +6,7 @@ This repository contains my custom OCaml standard library and build system.
|
|||||||
|
|
||||||
This is very bespoke for my requirements, and only something I use when writing code to be read and used by myself. In general, I do not recommend doing something like this. This repository exists because it shows off how one can effectively compile an OCaml project without the standard library but still expose the few functions they may need, a task made remarkably difficult by the way the compiler works, and because my implementations of some data structures and algorithms may be useful to people new to functional programming.
|
This is very bespoke for my requirements, and only something I use when writing code to be read and used by myself. In general, I do not recommend doing something like this. This repository exists because it shows off how one can effectively compile an OCaml project without the standard library but still expose the few functions they may need, a task made remarkably difficult by the way the compiler works, and because my implementations of some data structures and algorithms may be useful to people new to functional programming.
|
||||||
|
|
||||||
Also note that I use WSL for all OCaml programming, and this is my recommendation for Windows users. The only software dependencies for running and debugging code in this project are the OCaml compiler and make.
|
Also note that I use WSL for all OCaml programming, and this is my recommendation for Windows users. The only software dependencies for running and debugging code in this project are the OCaml compiler, gcc and make.
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ This library includes the following custom modules:
|
|||||||
- Array (for operations on mutable arrays)
|
- Array (for operations on mutable arrays)
|
||||||
- Bool (for basic operations on booleans)
|
- Bool (for basic operations on booleans)
|
||||||
- Char (for basic operations on characters)
|
- Char (for basic operations on characters)
|
||||||
|
- Console (for console IO)
|
||||||
- Fatal (for throwing exceptions, and making assertions)
|
- Fatal (for throwing exceptions, and making assertions)
|
||||||
- File (for file IO)
|
- File (for file IO)
|
||||||
- Float (for basic operations on floating point numbers)
|
- Float (for basic operations on floating point numbers)
|
||||||
@ -23,17 +24,11 @@ This library includes the following custom modules:
|
|||||||
- Map (functional map implemented as a red-black tree)
|
- Map (functional map implemented as a red-black tree)
|
||||||
- Option (functions for working with the option monad)
|
- Option (functions for working with the option monad)
|
||||||
- Queue (functional queue implemented as two lists)
|
- Queue (functional queue implemented as two lists)
|
||||||
- Random (for pseudorandom generation)
|
|
||||||
- Set (functional set implemented as a red-black tree)
|
- Set (functional set implemented as a red-black tree)
|
||||||
- Stack (functional stack data structure)
|
- Stack (functional stack data structure)
|
||||||
- String (for basic operations on strings)
|
- String (for basic operations on strings)
|
||||||
- Terminal (for terminal IO)
|
|
||||||
- Tree (functional generic tree type with some general functions to manipulate it)
|
- Tree (functional generic tree type with some general functions to manipulate it)
|
||||||
|
|
||||||
## Exposure of Functions from Standard Library
|
|
||||||
|
|
||||||
Some functions from the OCaml standard library are exposed through this library, for random number generation, file and terminal IO, and arrays. They are handled by direct reference to the `Stdlib` module and therefore all modules are compiled with the `-nopervasives` flag.
|
|
||||||
|
|
||||||
## Type Declarations and General Functions
|
## Type Declarations and General Functions
|
||||||
|
|
||||||
In order to prevent duplicate definitions of common types like collections, but still allow things like list literals to work, and to prevent the need of a type annotation at the module level, the `General` module is provided to be opened in code files which exposes types like `'a queue` and other collections. `General` also includes generic operators that should be opened file wide, such as function composition (`>>`). This should always be opened at the top of project files.
|
In order to prevent duplicate definitions of common types like collections, but still allow things like list literals to work, and to prevent the need of a type annotation at the module level, the `General` module is provided to be opened in code files which exposes types like `'a queue` and other collections. `General` also includes generic operators that should be opened file wide, such as function composition (`>>`). This should always be opened at the top of project files.
|
||||||
@ -56,7 +51,7 @@ We first create the file in the root directory, add the line `open General` to t
|
|||||||
|
|
||||||
```
|
```
|
||||||
build:
|
build:
|
||||||
ocamlopt $(CUSTOM_LIBRARY_LOCATION)/library.cmxa -o program
|
$(COMPILER) -I $(CUSTOM_LIBRARY_LOCATION) library$(AEXT) -o program
|
||||||
```
|
```
|
||||||
|
|
||||||
to this:
|
to this:
|
||||||
@ -64,11 +59,10 @@ to this:
|
|||||||
```
|
```
|
||||||
build:
|
build:
|
||||||
$(COMPILE) main.ml
|
$(COMPILE) main.ml
|
||||||
|
$(COMPILER) -I $(CUSTOM_LIBRARY_LOCATION) library$(AEXT) main$(EXT) -o program
|
||||||
ocamlopt $(CUSTOM_LIBRARY_LOCATION)/library.cmxa main.cmx -o program
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Any additional files that need to be added can be added in the same way, by adding the line to compile and adding the `.cmx` file to the final step.
|
Any additional files that need to be added can be added in the same way, by adding the line to compile and adding `filename$(EXT)` file to the final step.
|
||||||
|
|
||||||
If adding in other files, order them within both places according to the desired file order, and if adding an `.mli` file with the `.ml` file, simply compile with the `.mli` file as well, before the `.ml` file. For example:
|
If adding in other files, order them within both places according to the desired file order, and if adding an `.mli` file with the `.ml` file, simply compile with the `.mli` file as well, before the `.ml` file. For example:
|
||||||
|
|
||||||
@ -78,7 +72,6 @@ $(COMPILE) main.mli main.ml
|
|||||||
|
|
||||||
This leaves a project which can be built with `make build`, run with `make run` and cleaned with `make clean`. `make install` is also an implemented command which builds the project and cleans all except the executable.
|
This leaves a project which can be built with `make build`, run with `make run` and cleaned with `make clean`. `make install` is also an implemented command which builds the project and cleans all except the executable.
|
||||||
|
|
||||||
|
|
||||||
## Adding New Modules to the Standard Library
|
## Adding New Modules to the Standard Library
|
||||||
|
|
||||||
All new files added to the library need an `.ml` and `.mli` file in the `lib` folder.
|
All new files added to the library need an `.ml` and `.mli` file in the `lib` folder.
|
||||||
@ -89,10 +82,10 @@ Once the files exist, the compilation step needs to be added to the `makefile` w
|
|||||||
$(STANDARD_COMPILE) newModule.mli newModule.ml
|
$(STANDARD_COMPILE) newModule.mli newModule.ml
|
||||||
```
|
```
|
||||||
|
|
||||||
Then the final step within `build` also needs to be altered to include the corresponding `.cmx` file.
|
Then the `COMPILED_FILES` variable also needs to be altered to include the corresponding compiled files.
|
||||||
|
|
||||||
```
|
```
|
||||||
ocamlopt -a exposed.cmx int.cmx float.cmx option.cmx stack.cmx list.cmx map.cmx queue.cmx set.cmx tree.cmx string.cmx newModule.cmx -o $(LIB_NAME).cmxa
|
COMPILED_FILES = general$(EXT) fatal$(EXT) int$(EXT) float$(EXT) option$(EXT) stack$(EXT) list$(EXT) map$(EXT) queue$(EXT) set$(EXT) tree$(EXT) string$(EXT) char$(EXT) bool$(EXT) console$(EXT) file$(EXT) newModule$(EXT)
|
||||||
```
|
```
|
||||||
|
|
||||||
Just as with the project in the top level, file order should be consistent across compile lines and this final line.
|
Just as with the project in the top level, file order should be consistent across compile lines and this final line.
|
||||||
@ -101,8 +94,8 @@ Just as with the project in the top level, file order should be consistent acros
|
|||||||
|
|
||||||
One of the unfortunate consequences of the way OCaml's compilation works, is that there is a library called the core library (not to be confused with Jane Street's Core), documented [here](https://ocaml.org/manual/core.html), which contains some definitions for types and exceptions, yet does not include the code from the stdlib that uses them. When compiling with the `-nopervasives` flag, this is still included but without the standard library. While this makes sense from the perspective of having some fundamental exceptions always available, having types like `list` included makes it very annoying when implemented a custom standard library (with the benefit of list literals still functioning properly). This quirk is why my library has no type definition for `list`, `bool`, `option`, etc. but still uses these types.
|
One of the unfortunate consequences of the way OCaml's compilation works, is that there is a library called the core library (not to be confused with Jane Street's Core), documented [here](https://ocaml.org/manual/core.html), which contains some definitions for types and exceptions, yet does not include the code from the stdlib that uses them. When compiling with the `-nopervasives` flag, this is still included but without the standard library. While this makes sense from the perspective of having some fundamental exceptions always available, having types like `list` included makes it very annoying when implemented a custom standard library (with the benefit of list literals still functioning properly). This quirk is why my library has no type definition for `list`, `bool`, `option`, etc. but still uses these types.
|
||||||
|
|
||||||
## Planned Change;
|
## Planned Changes
|
||||||
|
|
||||||
At some point I would like to remove all dependencies on the actual OCaml standard library by way of custom implementations for all the functions that currently reference the `Stdlib` module, and all external functions using code in the standard library.
|
At some point I would like to remove all dependencies on the actual OCaml standard library. Currently the only dependencies that exist are some external C functions with the string and array modules.
|
||||||
|
|
||||||
Unit tests are also planned for all collection modules, but have not been written yet.
|
Unit tests are also planned, but have not been written yet.
|
68
lib/array.ml
Normal file → Executable file
68
lib/array.ml
Normal file → Executable file
@ -1,27 +1,73 @@
|
|||||||
open General
|
open General
|
||||||
|
|
||||||
|
external unsafe_get: 'a array -> int -> 'a = "%array_unsafe_get"
|
||||||
|
external unsafe_set: 'a array -> int -> 'a -> unit = "%array_unsafe_set"
|
||||||
|
external create: int -> 'a -> 'a array = "caml_make_vect"
|
||||||
|
|
||||||
let of_list = Stdlib.Array.of_list
|
|
||||||
|
|
||||||
let length = Stdlib.Array.length
|
|
||||||
|
|
||||||
let concat = Stdlib.Array.concat
|
|
||||||
|
|
||||||
let append = Stdlib.Array.append
|
|
||||||
|
|
||||||
let get = Stdlib.Array.get
|
|
||||||
|
|
||||||
let set = Stdlib.Array.set
|
external length : 'a array -> int = "%array_length"
|
||||||
|
|
||||||
let map = Stdlib.Array.map
|
external get : 'a array -> int -> 'a = "%array_safe_get"
|
||||||
|
|
||||||
let create = Stdlib.Array.init
|
external set : 'a array -> int -> 'a -> unit = "%array_safe_set"
|
||||||
|
|
||||||
let heap_sort = Stdlib.Array.sort
|
let of_list = function
|
||||||
|
| [] -> [||]
|
||||||
|
| x :: xs as l ->
|
||||||
|
let a = create (List.length l) x in
|
||||||
|
let rec fill i = function
|
||||||
|
| [] ->
|
||||||
|
a
|
||||||
|
| x::xs ->
|
||||||
|
unsafe_set a i x;
|
||||||
|
fill Int.(i + 1) xs
|
||||||
|
in
|
||||||
|
fill 1 xs
|
||||||
|
|
||||||
let merge_sort = Stdlib.Array.stable_sort
|
let create (length : int) (f : int -> 'a) : 'a array =
|
||||||
|
if length = 0 then
|
||||||
|
[||]
|
||||||
|
else if length < 0 then
|
||||||
|
Fatal.failwith "Cannot create an array with a size less than 0."
|
||||||
|
else
|
||||||
|
let result = create length (f 0) in
|
||||||
|
for i = 1 to Int.(length - 1) do
|
||||||
|
unsafe_set result i (f i)
|
||||||
|
done;
|
||||||
|
result
|
||||||
|
|
||||||
let copy = Stdlib.Array.copy
|
let append (arr1 : 'a array) (arr2 : 'b array) =
|
||||||
|
let open Int in
|
||||||
|
let arr1_length = length arr1 in
|
||||||
|
let arr2_length = length arr2 in
|
||||||
|
|
||||||
|
let init i =
|
||||||
|
if i < arr1_length then
|
||||||
|
get arr1 i
|
||||||
|
else
|
||||||
|
(get arr2 (i - arr1_length))
|
||||||
|
in
|
||||||
|
|
||||||
|
create (arr1_length + arr2_length) init
|
||||||
|
|
||||||
|
let concat (arrays : 'a array list) : 'a array =
|
||||||
|
arrays |> List.foldl append [||]
|
||||||
|
|
||||||
|
let map_mutate (f : 'a -> 'a) (arr : 'a array) : unit =
|
||||||
|
let open Int in
|
||||||
|
for i = 0 to length arr - 1 do
|
||||||
|
set arr i ((get arr i) |> f);
|
||||||
|
done;;
|
||||||
|
|
||||||
|
let copy (arr : 'a array) =
|
||||||
|
create (length arr) (fun i -> get arr i)
|
||||||
|
|
||||||
|
let map (f : 'a -> 'b) (arr : 'a array) : 'b array =
|
||||||
|
create (length arr) (fun i -> (get arr i) |> f)
|
||||||
|
|
||||||
let linear_search (arr : 'a array) (value : 'a) =
|
let linear_search (arr : 'a array) (value : 'a) =
|
||||||
let i = ref 0 in
|
let i = ref 0 in
|
||||||
|
12
lib/array.mli
Normal file → Executable file
12
lib/array.mli
Normal file → Executable file
@ -3,24 +3,22 @@ open General
|
|||||||
|
|
||||||
val of_list : 'a list -> 'a array
|
val of_list : 'a list -> 'a array
|
||||||
|
|
||||||
val length : 'a array -> int
|
external length : 'a array -> int = "%array_length"
|
||||||
|
|
||||||
val concat : 'a array list -> 'a array
|
val concat : 'a array list -> 'a array
|
||||||
|
|
||||||
val append : 'a array -> 'a array -> 'a array
|
val append : 'a array -> 'a array -> 'a array
|
||||||
|
|
||||||
val get : 'a array -> int -> 'a
|
external get: 'a array -> int -> 'a = "%array_safe_get"
|
||||||
|
|
||||||
val set : 'a array -> int -> 'a -> unit
|
external set: 'a array -> int -> 'a -> unit = "%array_safe_set"
|
||||||
|
|
||||||
|
val map_mutate : ('a -> 'a) -> 'a array -> unit
|
||||||
|
|
||||||
val map : ('a -> 'b) -> 'a array -> 'b array
|
val map : ('a -> 'b) -> 'a array -> 'b array
|
||||||
|
|
||||||
val create : int -> (int -> 'a) -> 'a array
|
val create : int -> (int -> 'a) -> 'a array
|
||||||
|
|
||||||
val heap_sort : ('a -> 'a -> int) -> 'a array -> unit
|
|
||||||
|
|
||||||
val merge_sort : ('a -> 'a -> int) -> 'a array -> unit
|
|
||||||
|
|
||||||
val copy : 'a array -> 'a array
|
val copy : 'a array -> 'a array
|
||||||
|
|
||||||
val linear_search : 'a array -> 'a -> 'a
|
val linear_search : 'a array -> 'a -> 'a
|
||||||
|
0
lib/bool.ml
Normal file → Executable file
0
lib/bool.ml
Normal file → Executable file
0
lib/bool.mli
Normal file → Executable file
0
lib/bool.mli
Normal file → Executable file
0
lib/char.ml
Normal file → Executable file
0
lib/char.ml
Normal file → Executable file
0
lib/char.mli
Normal file → Executable file
0
lib/char.mli
Normal file → Executable file
8
lib/console.ml
Executable file
8
lib/console.ml
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
open General
|
||||||
|
|
||||||
|
external print : string -> unit = "print"
|
||||||
|
|
||||||
|
external read_line : int -> string = "read_line"
|
||||||
|
|
||||||
|
let print_all (contents : string list) : unit =
|
||||||
|
print (String.concat contents)
|
10
lib/console.mli
Executable file
10
lib/console.mli
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
open General
|
||||||
|
|
||||||
|
(** Prints the provided string to the console. *)
|
||||||
|
external print : string -> unit = "print"
|
||||||
|
|
||||||
|
(** Reads a line from the console until a new line or EOF, using the specified buffer size. *)
|
||||||
|
external read_line : int -> string = "read_line"
|
||||||
|
|
||||||
|
(** Displays all provided strings to the console in order. *)
|
||||||
|
val print_all : string list -> unit
|
36
lib/console_external.c
Executable file
36
lib/console_external.c
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/alloc.h>
|
||||||
|
|
||||||
|
CAMLprim value print(value data)
|
||||||
|
{
|
||||||
|
CAMLparam1(data);
|
||||||
|
const char *data_string = String_val(data);
|
||||||
|
|
||||||
|
printf("%s", data_string);
|
||||||
|
|
||||||
|
return Val_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAMLprim value read_line(value input_length)
|
||||||
|
{
|
||||||
|
CAMLparam1(input_length);
|
||||||
|
const int input_length_int = Int_val(input_length);
|
||||||
|
|
||||||
|
char *input_line = malloc(sizeof (char) * input_length_int + 1);
|
||||||
|
char *result = fgets(input_line, input_length_int + 1, stdin);
|
||||||
|
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
printf("Failed to read input line from stdin.\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAMLlocal1(return_string);
|
||||||
|
|
||||||
|
return_string = caml_copy_string(input_line);
|
||||||
|
|
||||||
|
free(input_line);
|
||||||
|
CAMLreturn(return_string);
|
||||||
|
}
|
0
lib/fatal.ml
Normal file → Executable file
0
lib/fatal.ml
Normal file → Executable file
0
lib/fatal.mli
Normal file → Executable file
0
lib/fatal.mli
Normal file → Executable file
0
lib/file.ml
Normal file → Executable file
0
lib/file.ml
Normal file → Executable file
0
lib/file.mli
Normal file → Executable file
0
lib/file.mli
Normal file → Executable file
90
lib/file_external.c
Executable file
90
lib/file_external.c
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <caml/mlvalues.h>
|
||||||
|
#include <caml/memory.h>
|
||||||
|
#include <caml/alloc.h>
|
||||||
|
|
||||||
|
CAMLprim value write_all_lines(value file_path, value contents)
|
||||||
|
{
|
||||||
|
CAMLparam2(contents, file_path);
|
||||||
|
|
||||||
|
const char *contents_string = String_val(contents);
|
||||||
|
const char *file_path_string = String_val(file_path);
|
||||||
|
|
||||||
|
FILE *fp = fopen(file_path_string, "w");
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
printf("File %s was not opened correctly.\n", file_path_string);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "%s", contents_string);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return Val_unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
long file_length_from_pointer(FILE *fp)
|
||||||
|
{
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long size = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
long file_length(value file_path)
|
||||||
|
{
|
||||||
|
CAMLparam1(file_path);
|
||||||
|
const char *file_path_string = String_val(file_path);
|
||||||
|
|
||||||
|
FILE *fp = fopen(file_path_string, "r");
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
printf("File %s was not opened correctly.\n", file_path_string);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
long length = file_length_from_pointer(fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return Val_long(length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CAMLprim value read_all_lines(value file_path)
|
||||||
|
{
|
||||||
|
// Copy input from value to c string.
|
||||||
|
CAMLparam1(file_path);
|
||||||
|
const char *file_path_string = String_val(file_path);
|
||||||
|
|
||||||
|
// Open the file.
|
||||||
|
FILE *fp = fopen(file_path_string, "r");
|
||||||
|
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
printf("File %s was not opened correctly.\n", file_path_string);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the file length.
|
||||||
|
long length = file_length_from_pointer(fp);
|
||||||
|
|
||||||
|
// Allocate the buffer
|
||||||
|
char *buffer = malloc(sizeof (char) * length + 1);
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
// Read the file.
|
||||||
|
size_t read_size = fread(buffer, sizeof (char), length, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// Create the OCaml return value and copy over.
|
||||||
|
CAMLlocal1(file_contents);
|
||||||
|
file_contents = caml_copy_string(buffer);
|
||||||
|
|
||||||
|
// Free the buffer.
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return file_contents;
|
||||||
|
}
|
0
lib/float.ml
Normal file → Executable file
0
lib/float.ml
Normal file → Executable file
0
lib/float.mli
Normal file → Executable file
0
lib/float.mli
Normal file → Executable file
0
lib/general.ml
Normal file → Executable file
0
lib/general.ml
Normal file → Executable file
0
lib/general.mli
Normal file → Executable file
0
lib/general.mli
Normal file → Executable file
0
lib/int.ml
Normal file → Executable file
0
lib/int.ml
Normal file → Executable file
0
lib/int.mli
Normal file → Executable file
0
lib/int.mli
Normal file → Executable file
21
lib/list.ml
Normal file → Executable file
21
lib/list.ml
Normal file → Executable file
@ -152,5 +152,22 @@ let rec initialize_helper (f : int -> 'a) (length : int) (index : int) (acc : 'a
|
|||||||
let initialize (f : int -> 'a) (length : int) : 'a list =
|
let initialize (f : int -> 'a) (length : int) : 'a list =
|
||||||
initialize_helper f length 0 []
|
initialize_helper f length 0 []
|
||||||
|
|
||||||
let of_array =
|
|
||||||
Stdlib.Array.to_list
|
|
||||||
|
|
||||||
|
|
||||||
|
external unsafe_get: 'a array -> int -> 'a = "%array_unsafe_get"
|
||||||
|
external array_length : 'a array -> int = "%array_length"
|
||||||
|
|
||||||
|
let rec of_array_helper arr i res =
|
||||||
|
let open Int in
|
||||||
|
if i < 0 then
|
||||||
|
res
|
||||||
|
else
|
||||||
|
of_array_helper arr (i - 1) (unsafe_get arr i :: res)
|
||||||
|
|
||||||
|
|
||||||
|
let of_array arr =
|
||||||
|
let open Int in
|
||||||
|
of_array_helper arr (array_length arr - 1) []
|
||||||
|
|
0
lib/list.mli
Normal file → Executable file
0
lib/list.mli
Normal file → Executable file
28
lib/makefile
Normal file → Executable file
28
lib/makefile
Normal file → Executable file
@ -1,11 +1,19 @@
|
|||||||
STANDARD_FLAGS = -O3
|
COMPILER = ocamlopt
|
||||||
STANDARD_COMPILE = ocamlopt $(STANDARD_FLAGS) -nopervasives -c
|
EXT = .cmx
|
||||||
|
AEXT = .cmxa
|
||||||
|
|
||||||
|
STANDARD_FLAGS = -nopervasives -O3
|
||||||
|
STANDARD_COMPILE = $(COMPILER) $(STANDARD_FLAGS) -c
|
||||||
|
STANDARD_COMPILE_WITH_C = $(COMPILER) -ccopt -fPIC -c
|
||||||
LIB_NAME = library
|
LIB_NAME = library
|
||||||
|
|
||||||
|
COMPILED_FILES = general$(EXT) fatal$(EXT) int$(EXT) float$(EXT) option$(EXT) stack$(EXT) list$(EXT) map$(EXT) queue$(EXT) set$(EXT) tree$(EXT) string$(EXT) char$(EXT) bool$(EXT) console$(EXT) file$(EXT)
|
||||||
|
C_LIBS_FOR_LINKING = -cclib -lconsole_external -cclib -lfile_external
|
||||||
|
|
||||||
build:
|
build:
|
||||||
make clean
|
make clean
|
||||||
|
|
||||||
ocamlopt $(STANDARD_FLAGS) -nopervasives -c general.mli general.ml
|
$(COMPILER) $(STANDARD_FLAGS) -c general.mli general.ml
|
||||||
|
|
||||||
$(STANDARD_COMPILE) fatal.mli fatal.ml
|
$(STANDARD_COMPILE) fatal.mli fatal.ml
|
||||||
$(STANDARD_COMPILE) int.mli int.ml
|
$(STANDARD_COMPILE) int.mli int.ml
|
||||||
@ -20,12 +28,14 @@ build:
|
|||||||
$(STANDARD_COMPILE) string.mli string.ml
|
$(STANDARD_COMPILE) string.mli string.ml
|
||||||
$(STANDARD_COMPILE) char.mli char.ml
|
$(STANDARD_COMPILE) char.mli char.ml
|
||||||
$(STANDARD_COMPILE) bool.mli bool.ml
|
$(STANDARD_COMPILE) bool.mli bool.ml
|
||||||
$(STANDARD_COMPILE) terminal.mli terminal.ml
|
$(STANDARD_COMPILE_WITH_C) console_external.c console.mli console.ml
|
||||||
$(STANDARD_COMPILE) file.mli file.ml
|
ocamlmklib console_external.o -o console_external
|
||||||
$(STANDARD_COMPILE) array.mli array.ml
|
$(STANDARD_COMPILE_WITH_C) file_external.c file.mli file.ml
|
||||||
$(STANDARD_COMPILE) random.mli random.ml
|
ocamlmklib file_external.o -o file_external
|
||||||
|
|
||||||
ocamlopt -a general.cmx fatal.cmx int.cmx float.cmx option.cmx stack.cmx list.cmx map.cmx queue.cmx set.cmx tree.cmx string.cmx char.cmx bool.cmx terminal.cmx file.cmx array.cmx random.cmx -o $(LIB_NAME).cmxa
|
$(STANDARD_COMPILE) array.mli array.ml
|
||||||
|
|
||||||
|
$(COMPILER) -a $(C_LIBS_FOR_LINKING) $(COMPILED_FILES) -o library.cmxa
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma
|
rm -f *.o *.a *.s *.so *.cmi *.cmx *.cmxa *.cmo *.cma
|
||||||
|
0
lib/map.ml
Normal file → Executable file
0
lib/map.ml
Normal file → Executable file
0
lib/map.mli
Normal file → Executable file
0
lib/map.mli
Normal file → Executable file
0
lib/option.ml
Normal file → Executable file
0
lib/option.ml
Normal file → Executable file
0
lib/option.mli
Normal file → Executable file
0
lib/option.mli
Normal file → Executable file
5
lib/queue.ml
Normal file → Executable file
5
lib/queue.ml
Normal file → Executable file
@ -2,9 +2,10 @@ open General
|
|||||||
|
|
||||||
open List
|
open List
|
||||||
|
|
||||||
|
|
||||||
let enqueue (a : 'a) (qu : 'a queue) : 'a queue =
|
let enqueue (a : 'a) (qu : 'a queue) : 'a queue =
|
||||||
{ qu with front = a :: qu.back }
|
match qu.front with
|
||||||
|
| [] -> { front = [a]; back = [] }
|
||||||
|
| _ -> { qu with back = a :: qu.back }
|
||||||
|
|
||||||
let dequeue (qu : 'a queue) : ('a option * 'a queue) =
|
let dequeue (qu : 'a queue) : ('a option * 'a queue) =
|
||||||
match qu.front with
|
match qu.front with
|
||||||
|
0
lib/queue.mli
Normal file → Executable file
0
lib/queue.mli
Normal file → Executable file
@ -1,17 +0,0 @@
|
|||||||
open General
|
|
||||||
|
|
||||||
|
|
||||||
let init = Stdlib.Random.self_init
|
|
||||||
|
|
||||||
|
|
||||||
let integer low high =
|
|
||||||
init ();
|
|
||||||
Int.((Stdlib.Random.int (high - low)) + low)
|
|
||||||
|
|
||||||
let float low high =
|
|
||||||
init ();
|
|
||||||
Float.((Stdlib.Random.float (high - low)) + low)
|
|
||||||
|
|
||||||
let boolean =
|
|
||||||
init ();
|
|
||||||
Stdlib.Random.bool
|
|
@ -1,11 +0,0 @@
|
|||||||
open General
|
|
||||||
|
|
||||||
|
|
||||||
(** Generates a random integer between low (inclusive) and high (exclusive). *)
|
|
||||||
val integer : int -> int -> int
|
|
||||||
|
|
||||||
(** Generates a random float between low (inclusive) and high (exclusive). *)
|
|
||||||
val float : float -> float -> float
|
|
||||||
|
|
||||||
(** Generates a random boolean at even odds. *)
|
|
||||||
val boolean : unit -> bool
|
|
0
lib/set.ml
Normal file → Executable file
0
lib/set.ml
Normal file → Executable file
0
lib/set.mli
Normal file → Executable file
0
lib/set.mli
Normal file → Executable file
0
lib/stack.ml
Normal file → Executable file
0
lib/stack.ml
Normal file → Executable file
0
lib/stack.mli
Normal file → Executable file
0
lib/stack.mli
Normal file → Executable file
5
lib/string.ml
Normal file → Executable file
5
lib/string.ml
Normal file → Executable file
@ -11,6 +11,8 @@ external format_float : string -> float -> string = "caml_format_float"
|
|||||||
|
|
||||||
external length : string -> int = "%string_length"
|
external length : string -> int = "%string_length"
|
||||||
|
|
||||||
|
external get : string -> int -> char = "%string_safe_get"
|
||||||
|
|
||||||
let of_int n =
|
let of_int n =
|
||||||
format_int "%d" n
|
format_int "%d" n
|
||||||
|
|
||||||
@ -31,6 +33,8 @@ let ( + ) s1 s2 =
|
|||||||
|
|
||||||
bytes_unsafe_to_string s
|
bytes_unsafe_to_string s
|
||||||
|
|
||||||
|
let concat : string list -> string =
|
||||||
|
List.foldl (fun s m -> s + m) ""
|
||||||
|
|
||||||
external string_get : string -> int -> char = "%string_safe_get"
|
external string_get : string -> int -> char = "%string_safe_get"
|
||||||
let valid_float_lexem s =
|
let valid_float_lexem s =
|
||||||
@ -44,6 +48,5 @@ let valid_float_lexem s =
|
|||||||
|
|
||||||
loop 0
|
loop 0
|
||||||
|
|
||||||
|
|
||||||
let of_float f =
|
let of_float f =
|
||||||
valid_float_lexem (format_float "%.12g" f)
|
valid_float_lexem (format_float "%.12g" f)
|
||||||
|
6
lib/string.mli
Normal file → Executable file
6
lib/string.mli
Normal file → Executable file
@ -4,6 +4,9 @@ open General
|
|||||||
(** Calculates the length of the provided string. *)
|
(** Calculates the length of the provided string. *)
|
||||||
external length : string -> int = "%string_length"
|
external length : string -> int = "%string_length"
|
||||||
|
|
||||||
|
(** Gets the character at the specified index. *)
|
||||||
|
external get : string -> int -> char = "%string_safe_get"
|
||||||
|
|
||||||
(** Converts an int to a string. *)
|
(** Converts an int to a string. *)
|
||||||
val of_int : int -> string
|
val of_int : int -> string
|
||||||
|
|
||||||
@ -15,3 +18,6 @@ val of_bool : bool -> string
|
|||||||
|
|
||||||
(** Concatenates two strings together in the provided order. *)
|
(** Concatenates two strings together in the provided order. *)
|
||||||
val ( + ) : string -> string -> string
|
val ( + ) : string -> string -> string
|
||||||
|
|
||||||
|
(** Concatenates a list of strings into a single string in sequence. *)
|
||||||
|
val concat : string list -> string
|
@ -1,8 +0,0 @@
|
|||||||
open General
|
|
||||||
|
|
||||||
|
|
||||||
let printf = Stdlib.Printf.printf
|
|
||||||
|
|
||||||
let print s = printf "%s" s
|
|
||||||
|
|
||||||
let read_line = Stdlib.read_line
|
|
@ -1,11 +0,0 @@
|
|||||||
open General
|
|
||||||
|
|
||||||
|
|
||||||
(** Formatted print to terminal. *)
|
|
||||||
val printf : ('a, Stdlib.out_channel, unit) Stdlib.format -> 'a
|
|
||||||
|
|
||||||
(** Prints the provided string to the terminal. *)
|
|
||||||
val print : string -> unit
|
|
||||||
|
|
||||||
(** Reads an input line from the terminal. *)
|
|
||||||
val read_line : unit -> string
|
|
0
lib/tree.ml
Normal file → Executable file
0
lib/tree.ml
Normal file → Executable file
0
lib/tree.mli
Normal file → Executable file
0
lib/tree.mli
Normal file → Executable file
11
makefile
Normal file → Executable file
11
makefile
Normal file → Executable file
@ -1,14 +1,19 @@
|
|||||||
|
COMPILER = ocamlopt
|
||||||
|
EXT = .cmx
|
||||||
|
AEXT = .cmxa
|
||||||
|
|
||||||
CUSTOM_LIBRARY_LOCATION = lib
|
CUSTOM_LIBRARY_LOCATION = lib
|
||||||
COMPILE = ocamlopt -O3 -nopervasives -I $(CUSTOM_LIBRARY_LOCATION) -c
|
STANDARD_FLAGS = -nopervasives -O3
|
||||||
|
COMPILE = $(COMPILER) $(STANDARD_FLAGS) -I $(CUSTOM_LIBRARY_LOCATION) -c
|
||||||
|
|
||||||
build:
|
build:
|
||||||
ocamlopt $(CUSTOM_LIBRARY_LOCATION)/library.cmxa -o program
|
$(COMPILER) -I $(CUSTOM_LIBRARY_LOCATION) library$(AEXT) -o program
|
||||||
|
|
||||||
mostlyclean:
|
mostlyclean:
|
||||||
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma
|
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma program
|
rm -f *.o *.a *.s *.so *.cmi *.cmx *.cmxa *.cmo *.cma program
|
||||||
|
|
||||||
make install:
|
make install:
|
||||||
make build
|
make build
|
||||||
|
Loading…
Reference in New Issue
Block a user