new modules and neatened exposure of official stdlib code

This commit is contained in:
Aaron Manning 2022-02-04 14:06:51 +11:00 committed by aaron-jack-manning
parent e9368e17c1
commit e25b69bd44
41 changed files with 389 additions and 224 deletions

View File

@ -12,15 +12,18 @@ Also note that I use WSL for all OCaml programming, and this is my recommendatio
This library includes the following custom modules:
- Array (for operations on mutable arrays)
- Bool (for basic operations on booleans)
- Char (for basic operations on characters)
- Fatal (for throwing exceptions, and making assertions)
- File (for file IO)
- Float (for basic operations on floating point numbers)
- Int (for basic operations on integers)
- List (functional list data structure)
- Map (functional map implemented as a red-black tree)
- Option (functions for working with the option monad)
- Queue (functional queue implemented as two lists)
- Random (for pseudorandom generation)
- Set (functional set implemented as a red-black tree)
- Stack (functional stack data structure)
- String (for basic operations on strings)
@ -29,7 +32,7 @@ This library includes the following custom modules:
## Exposure of Functions from Standard Library
Some functions from the OCaml standard library are exposed through this library. They are handled by the `FromStdlib` module which SHOULD NOT be accessed directly in projects using this library. All functions and types from this module that are exposed to be used in projects are redefined in another module and should be accessed there. The reason for this module is to allow the rest of the modules to be compile with the `-nopervasives` flag yet still access a few of the official OCaml standard module functions.
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
@ -89,7 +92,7 @@ $(STANDARD_COMPILE) newModule.mli newModule.ml
Then the final step within `build` also needs to be altered to include the corresponding `.cmx` file.
```
ocamlopt -a fromStdlib.cmx 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
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
```
Just as with the project in the top level, file order should be consistent across compile lines and this final line.
@ -98,18 +101,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.
## Planned Changes
## Planned Change;
The following modules are some that I plan on introducing in future iterations of this project:
- Array: for operations with mutable arrays.
- Random: for random number generation.
- File: for file IO.
I also intend on modifying the following modules:
- Terminal: this module still needs input functions.
## Tests
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.
Unit tests are also planned for all collection modules, but have not been written yet.

50
lib/array.ml Normal file
View File

@ -0,0 +1,50 @@
open General
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
let map = Stdlib.Array.map
let create = Stdlib.Array.init
let heap_sort = Stdlib.Array.sort
let merge_sort = Stdlib.Array.stable_sort
let copy = Stdlib.Array.copy
let linear_search (arr : 'a array) (value : 'a) =
let i = ref 0 in
while (!i < length arr) & (get arr !i <> value) do
i := Int.(!i + 1)
done;
get arr !i
let rec binary_search_helper (arr : 'a array) (value : 'a) (first : int) (last : int) =
let midpoint = Int.((first + last) / 2) in
if midpoint < first or midpoint > last then
None
else if value < (get arr midpoint) then
binary_search_helper arr value first Int.(midpoint - 1)
else if (get arr midpoint) < value then
binary_search_helper arr value Int.(midpoint + 1) last
else if get arr midpoint = value then
Some (get arr midpoint)
else
None
let binary_search (arr : 'a array) (value : 'a) =
binary_search_helper arr value 0 Int.(length arr - 1)

28
lib/array.mli Normal file
View File

@ -0,0 +1,28 @@
open General
val of_list : 'a list -> 'a array
val length : 'a array -> int
val concat : 'a array list -> 'a array
val append : 'a array -> 'a array -> 'a array
val get : 'a array -> int -> 'a
val set : 'a array -> int -> 'a -> unit
val map : ('a -> 'b) -> 'a array -> 'b 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 linear_search : 'a array -> 'a -> 'a
val binary_search : 'a array -> 'a -> 'a option

View File

@ -1,3 +1,7 @@
open General
let of_string = FromStdlib.bool_of_string_opt
let of_string = function
| "true" -> Some true
| "false" -> Some false
| _ -> None

View File

@ -1,4 +1,5 @@
open General
(** Converts the string to a bool, returning option type to account for invalid strings. *)
val of_string : string -> bool option

View File

@ -1,3 +1,11 @@
open General
let of_int = FromStdlib.char_of_int
external unsafe_char_of_int : int -> char = "%identity"
let of_int n =
if n < 0 or n > 255 then
None
else
Some (unsafe_char_of_int n)

View File

@ -1,4 +1,5 @@
open General
(** Converts an int to a char. *)
val of_int : int -> char
val of_int : int -> char option

View File

@ -1,6 +1,10 @@
open General
let failwith = FromStdlib.failwith
external raise : exn -> 'a = "%raise"
let failwith m = raise (Failure m)
let guarantee b =
if not b then
@ -8,4 +12,7 @@ let guarantee b =
let guarantee_equal a b =
if a <> b then
failwith "guarantee_equal failed."
failwith "guarantee_equal failed."

View File

@ -1,5 +1,6 @@
open General
(** Throws an exception with a message. *)
val failwith : string -> 'a

29
lib/file.ml Normal file
View File

@ -0,0 +1,29 @@
open General
let open_out = Stdlib.open_out
let close_out = Stdlib.close_out
let printf = Stdlib.Printf.fprintf
let write_all_text filepath text =
let channel = open_out filepath in
let _ = printf channel "%s" text in
let _ = close_out channel in
()
let open_in = Stdlib.open_in
let close_in = Stdlib.close_in
let read_n_chars = Stdlib.really_input_string
let in_channel_length = Stdlib.in_channel_length
let read_all_text filepath =
let channel = open_in filepath in
let contents = read_n_chars channel (in_channel_length channel) in
let _ = close_in channel in
contents

26
lib/file.mli Normal file
View File

@ -0,0 +1,26 @@
open General
(** Opens and returns an output channel at the specified path. *)
val open_out : string -> Stdlib.out_channel
(** Closes the provided output channel. *)
val close_out : Stdlib.out_channel -> unit
(** Formatted printing to a provided output channel. *)
val printf : Stdlib.out_channel -> ('a, Stdlib.out_channel, unit) Stdlib.format -> 'a
(** Writes the given string to a file at the specified filepath. *)
val write_all_text : string -> string -> unit
(** Opens and returns an input channel at the specified path. *)
val open_in : string -> Stdlib.in_channel
(** Closes the provided input channel. *)
val close_in : Stdlib.in_channel -> unit
(** Reads the specified number of characters from the provided input channel as a string. *)
val read_n_chars : Stdlib.in_channel -> int -> string
(** Reads from the specified file as a string. *)
val read_all_text : string -> string

View File

@ -1,11 +1,22 @@
open General
let ( + ) a b = FromStdlib.plus_float a b
let ( - ) a b = FromStdlib.minus_float a b
external ( + ) : float -> float -> float = "%addfloat"
let ( * ) a b = FromStdlib.multiply_float a b
external ( - ) : float -> float -> float = "%subfloat"
let ( / ) a b = FromStdlib.divide_float a b
external ( * ) : float -> float -> float = "%mulfloat"
let of_string = FromStdlib.float_of_string_opt
external ( / ) : float -> float -> float = "%divfloat"
external float_of_string : string -> float = "caml_float_of_string"
let of_string s =
try
Some (float_of_string s)
with
Failure _ -> None
external of_int : int -> float = "%floatofint"

View File

@ -1,12 +1,16 @@
open General
val ( + ) : float -> float -> float
val ( - ) : float -> float -> float
external ( + ) : float -> float -> float = "%addfloat"
val ( * ) : float -> float -> float
external ( - ) : float -> float -> float = "%subfloat"
val ( / ) : float -> float -> float
external ( * ) : float -> float -> float = "%mulfloat"
external ( / ) : float -> float -> float = "%divfloat"
(** Converts the string to a float, returning option type to account for invalid strings. *)
val of_string : string -> float option
val of_string : string -> float option
(** Converts the int to a float. *)
val of_int : int -> float

View File

@ -1,79 +0,0 @@
(* https://github.com/ocaml/ocaml/blob/cce52acc7c7903e92078e9fe40745e11a1b944f0/stdlib/pervasives.ml *)
(* For fatal.ml *)
let failwith = Stdlib.failwith
(* For terminal.ml *)
let printf = Printf.printf
type 'a printf_format = ('a, out_channel, unit) format
(* For int.ml *)
external int_of_char : char -> int = "%identity"
let int_of_string_opt = int_of_string_opt
external plus_int : int -> int -> int = "%addint"
external minus_int : int -> int -> int = "%subint"
external multiply_int : int -> int -> int = "%mulint"
external divide_int : int -> int -> int = "%divint"
external mod_int : int -> int -> int = "%modint"
(* For float.ml *)
let float_of_string_opt = float_of_string_opt
external plus_float : float -> float -> float = "%addfloat"
external minus_float : float -> float -> float = "%subfloat"
external multiply_float : float -> float -> float = "%mulfloat"
external divide_float : float -> float -> float = "%divfloat"
(* For char.ml *)
let char_of_int = char_of_int
(* For string.ml *)
let string_of_bool = string_of_bool
let string_of_int = string_of_int
let string_of_float = string_of_float
external string_length : string -> int = "%string_length"
(* This block are not exposed *)
external bytes_create : int -> bytes = "caml_create_bytes"
external string_blit : string -> int -> bytes -> int -> int -> unit
= "caml_blit_string" [@@noalloc]
external bytes_blit : bytes -> int -> bytes -> int -> int -> unit
= "caml_blit_bytes" [@@noalloc]
external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string"
let string_concat s1 s2 =
let l1 = string_length s1 and l2 = string_length s2 in
let s = bytes_create (l1 + l2) in
string_blit s1 0 s 0 l1;
string_blit s2 0 s l1 l2;
bytes_unsafe_to_string s
(* For bool.ml *)
let bool_of_string_opt = bool_of_string_opt
(* For general.ml *)
external equal : 'a -> 'a -> bool = "%equal"
external not_equal : 'a -> 'a -> bool = "%notequal"
external less_than : 'a -> 'a -> bool = "%lessthan"
external greater_than : 'a -> 'a -> bool = "%greaterthan"
external less_than_or_equal : 'a -> 'a -> bool = "%lessequal"
external greater_than_or_equal : 'a -> 'a -> bool = "%greaterequal"
external not : bool -> bool = "%boolnot"
external or_ : bool -> bool -> bool = "%sequor"
external and_ : bool -> bool -> bool = "%sequand"
external pipeline : 'a -> ('a -> 'b) -> 'b = "%revapply"
external ignore : 'a -> unit = "%ignore"

View File

@ -1,61 +0,0 @@
(* For fatal.ml *)
val failwith : string -> 'a
(* For terminal.ml *)
val printf : ('a, out_channel, unit) format -> 'a
type 'a printf_format = ('a, out_channel, unit) format
(* For int.ml *)
external int_of_char : char -> int = "%identity"
val int_of_string_opt : string -> int option
external plus_int : int -> int -> int = "%addint"
external minus_int : int -> int -> int = "%subint"
external multiply_int : int -> int -> int = "%mulint"
external divide_int : int -> int -> int = "%divint"
external mod_int : int -> int -> int = "%modint"
(* For float.ml *)
val float_of_string_opt : string -> float option
external plus_float : float -> float -> float = "%addfloat"
external minus_float : float -> float -> float = "%subfloat"
external multiply_float : float -> float -> float = "%mulfloat"
external divide_float : float -> float -> float = "%divfloat"
(* For char.ml *)
val char_of_int : int -> char
(* For string.ml *)
val string_of_bool : bool -> string
val string_of_int : int -> string
val string_of_float : float -> string
external string_length : string -> int = "%string_length"
val string_concat : string -> string -> string
(* For bool.ml *)
val bool_of_string_opt : string -> bool option
(* For general.ml *)
external equal : 'a -> 'a -> bool = "%equal"
external not_equal : 'a -> 'a -> bool = "%notequal"
external less_than : 'a -> 'a -> bool = "%lessthan"
external greater_than : 'a -> 'a -> bool = "%greaterthan"
external less_than_or_equal : 'a -> 'a -> bool = "%lessequal"
external greater_than_or_equal : 'a -> 'a -> bool = "%greaterequal"
external not : bool -> bool = "%boolnot"
external or_ : bool -> bool -> bool = "%sequor"
external and_ : bool -> bool -> bool = "%sequand"
external pipeline : 'a -> ('a -> 'b) -> 'b = "%revapply"
external ignore : 'a -> unit = "%ignore"

View File

@ -12,7 +12,7 @@ type 'a tree =
| Leaf
| Branch of 'a * 'a tree list
let ignore = FromStdlib.ignore
let ignore (a : 'a) = ()
let id (x : 'a) = x
@ -20,23 +20,38 @@ let ( >> ) f g x = g (f x)
let ( << ) g f x = g (f x)
let ( |> ) = FromStdlib.pipeline
let ( |> ) f g = g f
let ( = ) = FromStdlib.equal
external ( = ) : 'a -> 'a -> bool = "%equal"
let ( <> ) = FromStdlib.not_equal
external ( <> ) : 'a -> 'a -> bool = "%notequal"
let ( < ) = FromStdlib.less_than
external ( < ) : 'a -> 'a -> bool = "%lessthan"
let ( > ) = FromStdlib.greater_than
external ( > ) : 'a -> 'a -> bool = "%greaterthan"
let ( <= ) = FromStdlib.less_than_or_equal
external ( <= ) : 'a -> 'a -> bool = "%lessequal"
let ( >= ) = FromStdlib.greater_than_or_equal
external ( >= ) : 'a -> 'a -> bool = "%greaterequal"
let not = FromStdlib.not
let not = function
| true -> false
| false -> true
let ( or ) = FromStdlib.or_
external ( or ) : bool -> bool -> bool = "%sequor"
external ( & ) : bool -> bool -> bool = "%sequand"
type 'a ref =
{ mutable contents : 'a }
let ref a =
{ contents = a }
let ( := ) (cell : 'a ref) (contents : 'a) =
cell.contents <- contents
let ( ! ) (cell : 'a ref) =
cell.contents
let ( & ) = FromStdlib.and_

View File

@ -1,6 +1,7 @@
(** Purely functional queue, implemented as a pair of lists. *)
type 'a queue = { front : 'a list; back : 'a list }
(** Result type for error handling. *)
type 'a result =
| Error of string
| Success of 'a
@ -10,7 +11,7 @@ type 'a stack =
| Empty
| Stacked of 'a * 'a stack
(* A purely functional tree with arbitrarily many branches at each node. *)
(**A purely functional tree with arbitrarily many branches at each node. *)
type 'a tree =
| Leaf
| Branch of 'a * 'a tree list
@ -31,28 +32,40 @@ val ( << ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
val ( |> ) : 'a -> ('a -> 'b) -> 'b
(** Checks for structural equality. *)
val ( = ) : 'a -> 'a -> bool
external ( = ) : 'a -> 'a -> bool = "%equal"
(** Checks for structural inequality. *)
val ( <> ) : 'a -> 'a -> bool
external ( <> ) : 'a -> 'a -> bool = "%notequal"
(** Polymorphic less than. *)
val ( < ) : 'a -> 'a -> bool
external ( < ) : 'a -> 'a -> bool = "%lessthan"
(** Polymorphic greater than. *)
val ( > ) : 'a -> 'a -> bool
external ( > ) : 'a -> 'a -> bool = "%greaterthan"
(** Polymorphic less than or equal to. *)
val ( <= ) : 'a -> 'a -> bool
external ( <= ) : 'a -> 'a -> bool = "%lessequal"
(** Polymorphic greater than or equal to. *)
val ( >= ) : 'a -> 'a -> bool
external ( >= ) : 'a -> 'a -> bool = "%greaterequal"
(** Logical negation. *)
val not : bool -> bool
(** Logical or (infix). *)
val ( or ) : bool -> bool -> bool
external ( or ) : bool -> bool -> bool = "%sequor"
(** Logical and. *)
val ( & ) : bool -> bool -> bool
external ( & ) : bool -> bool -> bool = "%sequand"
(** Reference cells for mutable variables. *)
type 'a ref = { mutable contents : 'a; }
(** Creates a reference cell. *)
val ref : 'a -> 'a ref
(** Updates a reference cell. *)
val ( := ) : 'a ref -> 'a -> unit
(** Returns the contents of a reference cell. *)
val ( ! ) : 'a ref -> 'a

View File

@ -1,16 +1,26 @@
open General
let ( + ) a b = FromStdlib.plus_int a b
let ( - ) a b = FromStdlib.minus_int a b
external ( + ) : int -> int -> int = "%addint"
let ( * ) a b = FromStdlib.multiply_int a b
external ( - ) : int -> int -> int = "%subint"
let ( / ) a b = FromStdlib.divide_int a b
external ( * ) : int -> int -> int = "%mulint"
let ( mod ) a b = FromStdlib.mod_int a b
external ( / ) : int -> int -> int = "%divint"
external ( mod ) : int -> int -> int = "%modint"
external of_char : char -> int = "%identity"
external int_of_string : string -> int = "caml_int_of_string"
let of_string s =
try
Some (int_of_string s)
with
| Failure _ -> None
let of_char = FromStdlib.int_of_char
let of_string = FromStdlib.int_of_string_opt

View File

@ -1,17 +1,18 @@
open General
val ( + ) : int -> int -> int
val ( - ) : int -> int -> int
external ( + ) : int -> int -> int = "%addint"
val ( * ) : int -> int -> int
external ( - ) : int -> int -> int = "%subint"
val ( / ) : int -> int -> int
external ( * ) : int -> int -> int = "%mulint"
val ( mod ) : int -> int -> int
external ( / ) : int -> int -> int = "%divint"
external ( mod ) : int -> int -> int = "%modint"
(** Converts the char to an int. *)
val of_char : char -> int
external of_char : char -> int = "%identity"
(** Converts the string to an int, returning option type to account for invalid strings. *)
val of_string : string -> int option

View File

@ -1,7 +1,15 @@
open General
let empty : 'a list = []
let rec length_helper (list : 'a list) (length : int) =
match list with
| [] -> length
| _ :: xs -> length_helper xs Int.(length + 1)
let length (list : 'a list) = length_helper list 0
let head (ls : 'a list) : 'a option =
match ls with
| x :: xs -> Some x
@ -142,4 +150,7 @@ let rec initialize_helper (f : int -> 'a) (length : int) (index : int) (acc : 'a
initialize_helper f length Int.(index + 1) ((f index) :: acc)
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

View File

@ -1,8 +1,12 @@
open General
(** The empty list *)
val empty : 'a list
(** Calculates the length of the given list. Runs in O(n) and should be stored rather then recalculated if many calls are made on an unchanging list. *)
val length : 'a list -> int
(** Returns Some [x] if [x] is the head of the list, or None for the empty list. Runs in O(1). *)
val head : 'a list -> 'a option
@ -55,4 +59,7 @@ val filter_rev_tr : ('a -> bool) -> 'a list -> 'a list
val find : ('a -> bool) -> 'a list -> ('a * int) option
(** Initializes a list using a length and a function from the index to the desired list value. Runs in O(n). *)
val initialize : (int -> 'a) -> int -> 'a list
val initialize : (int -> 'a) -> int -> 'a list
(* Creates a list from the provided array. *)
val of_array : 'a array -> 'a list

View File

@ -3,13 +3,10 @@ STANDARD_COMPILE = ocamlopt $(STANDARD_FLAGS) -nopervasives -c
LIB_NAME = library
build:
# fromStdlib manages things that need to be exposed from the standard library
ocamlopt $(STANDARD_FLAGS) -c fromStdlib.mli fromStdlib.ml
make clean
# types and functions that should be opened module wide
ocamlopt $(STANDARD_FLAGS) -nopervasives -c general.mli general.ml
# the following files make up the core custom standard library code
$(STANDARD_COMPILE) fatal.mli fatal.ml
$(STANDARD_COMPILE) int.mli int.ml
$(STANDARD_COMPILE) float.mli float.ml
@ -24,9 +21,11 @@ build:
$(STANDARD_COMPILE) char.mli char.ml
$(STANDARD_COMPILE) bool.mli bool.ml
$(STANDARD_COMPILE) terminal.mli terminal.ml
$(STANDARD_COMPILE) file.mli file.ml
$(STANDARD_COMPILE) array.mli array.ml
$(STANDARD_COMPILE) random.mli random.ml
ocamlopt -a fromStdlib.cmx 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 -o $(LIB_NAME).cmxa
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
clean:
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma

View File

@ -1,5 +1,6 @@
open General
module type Map = sig
type key

View File

@ -1,5 +1,6 @@
open General
module type Map = sig
(** The type of keys in the map. *)
type key

View File

@ -1,5 +1,6 @@
open General
let return (x : 'a) : 'a option = Some x
let ( ~= ) = return

View File

@ -1,5 +1,6 @@
open General
(* Monadic return for option type. Trivially boxes the variable of type 'a into a 'a option by applying the Some constructor. *)
val return : 'a -> 'a option

View File

@ -1,6 +1,8 @@
open General
open List
let enqueue (a : 'a) (qu : 'a queue) : 'a queue =
{ qu with front = a :: qu.back }

View File

@ -1,5 +1,6 @@
open General
(** Adds an element to the back of the queue, returning the new queue. Runs in O(1). *)
val enqueue : 'a -> 'a queue -> 'a queue

17
lib/random.ml Normal file
View File

@ -0,0 +1,17 @@
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

11
lib/random.mli Normal file
View File

@ -0,0 +1,11 @@
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

View File

@ -1,5 +1,6 @@
open General
module type RBTreeSet = sig
type member

View File

@ -1,5 +1,6 @@
open General
module type RBTreeSet = sig
(** Type of members in the set. *)
type member

View File

@ -1,5 +1,6 @@
open General
let pop (st : 'a stack) : 'a option * 'a stack =
match st with
| Empty -> (None, Empty)

View File

@ -1,5 +1,6 @@
open General
(** Removes the top element from the stack, returning a tuple of the new stack, and None if the stack was empty, or Some [x] if [x] was on top of the stack. Popping an empty stack will result in the returned stack also being empty. Runs in O(1). *)
val pop : 'a stack -> 'a option * 'a stack

View File

@ -1,11 +1,49 @@
open General
let ( + ) = FromStdlib.string_concat
let length = FromStdlib.string_length
external bytes_create : int -> bytes = "caml_create_bytes"
external string_blit : string -> int -> bytes -> int -> int -> unit = "caml_blit_string" [@@noalloc]
external bytes_blit : bytes -> int -> bytes -> int -> int -> unit = "caml_blit_bytes" [@@noalloc]
external bytes_unsafe_to_string : bytes -> string = "%bytes_to_string"
external format_int : string -> int -> string = "caml_format_int"
external format_float : string -> float -> string = "caml_format_float"
let of_int = FromStdlib.string_of_int
let of_float = FromStdlib.string_of_float
external length : string -> int = "%string_length"
let of_bool = FromStdlib.string_of_bool
let of_int n =
format_int "%d" n
let of_bool bool =
if bool then
"true"
else
"false"
let ( + ) s1 s2 =
let l1 = length s1 in
let l2 = length s2 in
let s = bytes_create Int.(l1 + l2) in
string_blit s1 0 s 0 l1;
string_blit s2 0 s l1 l2;
bytes_unsafe_to_string s
external string_get : string -> int -> char = "%string_safe_get"
let valid_float_lexem s =
let l = length s in
let rec loop i =
if i >= l then s + "." else
match string_get s i with
| '0' .. '9' | '-' -> loop Int.(i + 1)
| _ -> s
in
loop 0
let of_float f =
valid_float_lexem (format_float "%.12g" f)

View File

@ -1,10 +1,8 @@
open General
(** Concatenates two strings together in the provided order. *)
val ( + ) : string -> string -> string
(** Calculates the length of the provided string. *)
val length : string -> int
external length : string -> int = "%string_length"
(** Converts an int to a string. *)
val of_int : int -> string
@ -14,3 +12,6 @@ val of_float : float -> string
(** Converts a boolean to a string. *)
val of_bool : bool -> string
(** Concatenates two strings together in the provided order. *)
val ( + ) : string -> string -> string

View File

@ -1,6 +1,8 @@
open General
let printf = FromStdlib.printf
let printf = Stdlib.Printf.printf
let print s = printf "%s" s
let print s = printf "%s" s
let read_line = Stdlib.read_line

View File

@ -1,7 +1,11 @@
open General
(** Formatted print to terminal. *)
val printf : 'a FromStdlib.printf_format -> 'a
val printf : ('a, Stdlib.out_channel, unit) Stdlib.format -> 'a
(** Prints the provided string to the terminal. *)
val print : string -> unit
val print : string -> unit
(** Reads an input line from the terminal. *)
val read_line : unit -> string

View File

@ -1,5 +1,6 @@
open General
let combine (tr1 : 'a tree) (tr2 : 'a tree) (topBranch : 'a) : 'a tree =
Branch (topBranch, tr1 :: tr2 :: [])

View File

@ -1,5 +1,6 @@
open General
(* Combines two trees of the same type, with the specified value at the new top node. Runs in O(1). *)
val combine : 'a tree -> 'a tree -> 'a -> 'a tree

View File

@ -5,10 +5,10 @@ build:
ocamlopt $(CUSTOM_LIBRARY_LOCATION)/library.cmxa -o program
mostlyclean:
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma main.mli
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma
clean:
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma main.mli program
rm -f *.o *.a *.s *.cmi *.cmx *.cmxa *.cmo *.cma program
make install:
make build