├── .gitignore ├── .travis.yml ├── Changelog ├── LICENSE ├── README.md ├── dune-project ├── monomorphic.opam ├── src ├── dune ├── monomorphic.ml └── monomorphic.mli └── test ├── dune └── test.ml /.gitignore: -------------------------------------------------------------------------------- 1 | /_build 2 | /monomorphic.install 3 | .merlin 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-opam.sh 3 | script: bash -ex .travis-opam.sh 4 | env: 5 | global: 6 | - PINS="monomorphic:." 7 | - PACKAGE="monomorphic" 8 | matrix: 9 | - OCAML_VERSION=4.08 10 | - OCAML_VERSION=4.09 11 | - OCAML_VERSION=4.10 12 | - OCAML_VERSION=4.11 13 | - OCAML_VERSION=4.12 14 | -------------------------------------------------------------------------------- /Changelog: -------------------------------------------------------------------------------- 1 | 2.1.0 (28/10/2022) 2 | ------------------ 3 | 4 | - Improve performance when using external functions (fixes #4) 5 | - Add a dependency to cppo 6 | - Add support for OCaml 5.0 7 | 8 | 2.0 (28/09/2020) 9 | ---------------- 10 | 11 | - Add support for the `Stdlib` module from OCaml 4.07 12 | 13 | - Use the `Int` implementation by default instead of `None` in the `Stdlib` module. 14 | 15 | - Remove the `MakeInfix`, `MakeCmp` modules and `TY` module type 16 | 17 | - Monomorphise `Stdlib.List.assoc_opt` from OCaml 4.05 18 | 19 | - Monomorphise the `Stdlib.ListLabels` and `Stdlib.Pervasives` modules properly 20 | 21 | - Add the `Bool` and `String` modules to monomorphise the equality functions 22 | for `bool` and `string` respectively. 23 | 24 | - Now requires OCaml >= 4.08 and Dune >= 2.7 25 | 26 | 27 | 1.5 and prior versions 28 | ---------------------- 29 | 30 | - Has the `MakeInfix`, `MakeCmp` and `Make` functors to create new comparators 31 | for different types using polymorphic equality. 32 | 33 | - Has the `None`, `Int` and `Float` modules to monomorphise the equality 34 | functions to those specific types. 35 | 36 | - Has the `Stdlib` module to shadow completely the whole standard library. 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Kate 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ocaml-monomorphic is a small library used to shadow polymorphic operators (and functions) contained in Stdlib. 2 | It can be useful to avoid some mistakes and runtime errors due to OCaml's polymorphic comparison functions. 3 | 4 | ## Requirements 5 | 6 | This library only requires: 7 | * OCaml >= 4.08 8 | * Dune >= 2.7 9 | 10 | ## Usage 11 | 12 | :books: [API documentation](https://kit-ty-kate.github.io/ocaml-monomorphic) :books: 13 | 14 | Using dune, a simple usage would be: 15 | ``` 16 | (library 17 | (public_name your-lib) 18 | (libraries monomorphic) 19 | (flags :standard -open Monomorphic.Int)) 20 | ``` 21 | 22 | ---- 23 | 24 | [![Build Status](https://travis-ci.org/kit-ty-kate/ocaml-monomorphic.png?branch=master)](https://travis-ci.org/kit-ty-kate/ocaml-monomorphic) 25 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.7) 2 | (name monomorphic) 3 | (version 2.1.0) 4 | 5 | (formatting disabled) 6 | -------------------------------------------------------------------------------- /monomorphic.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | version: "2.1.0" 3 | synopsis: 4 | "A small library used to shadow polymorphic operators (and functions) contained in the stdlib" 5 | maintainer: ["Kate "] 6 | authors: ["Kate "] 7 | license: "MIT" 8 | tags: [ 9 | "polymorphic" "compare" "equal" "equality" "monomorphic" "unsafe" "safe" 10 | ] 11 | homepage: "https://github.com/kit-ty-kate/ocaml-monomorphic" 12 | doc: "https://kit-ty-kate.github.io/ocaml-monomorphic" 13 | dev-repo: "git+https://github.com/kit-ty-kate/ocaml-monomorphic.git" 14 | bug-reports: "https://github.com/kit-ty-kate/ocaml-monomorphic/issues" 15 | depends: [ 16 | "dune" {>= "2.7"} 17 | "ocaml" {>= "4.08"} 18 | "cppo" {>= "1.1.0"} 19 | "odoc" {with-doc} 20 | ] 21 | build: ["dune" "build" "-p" name "-j" jobs] 22 | run-test: ["dune" "runtest" "-p" name "-j" jobs] 23 | -------------------------------------------------------------------------------- /src/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (public_name monomorphic) 3 | (preprocess (action (run %{bin:cppo} -V OCAML:%{ocaml_version} %{input-file})))) 4 | -------------------------------------------------------------------------------- /src/monomorphic.ml: -------------------------------------------------------------------------------- 1 | (* Copyright (c) 2013-2017 Kate . *) 2 | (* See the LICENSE file at the top-level directory. *) 3 | 4 | [@@@ocaml.alert "-deprecated"] 5 | 6 | module Make (Ty : sig type t end) : sig 7 | external (=) : Ty.t -> Ty.t -> bool = "%equal" 8 | external (<>) : Ty.t -> Ty.t -> bool = "%notequal" 9 | external (<) : Ty.t -> Ty.t -> bool = "%lessthan" 10 | external (>) : Ty.t -> Ty.t -> bool = "%greaterthan" 11 | external (<=) : Ty.t -> Ty.t -> bool = "%lessequal" 12 | external (>=) : Ty.t -> Ty.t -> bool = "%greaterequal" 13 | external compare : Ty.t -> Ty.t -> int = "%compare" 14 | val min : Ty.t -> Ty.t -> Ty.t 15 | val max : Ty.t -> Ty.t -> Ty.t 16 | end = Stdlib 17 | 18 | module None : module type of Make(struct type t = unit end) = Stdlib 19 | module Int : module type of Make(struct type t = int end) = Stdlib 20 | module Bool : module type of Make(struct type t = bool end) = Stdlib 21 | module Float : module type of Make(struct type t = float end) = Stdlib 22 | module String : module type of Make(struct type t = string end) = Stdlib 23 | 24 | module Stdlib = struct 25 | module Stdlib = struct 26 | include Int 27 | 28 | module List = struct 29 | include List 30 | 31 | let mem a ~eq xs = List.exists (eq a) xs 32 | let assoc a ~eq xs = snd (List.find (fun (k,_) -> eq a k) xs) 33 | let assoc_opt a ~eq xs = Option.map snd (List.find_opt (fun (k,_) -> eq a k) xs) 34 | let mem_assoc a ~eq xs = List.exists (fun (k, _) -> eq k a) xs 35 | let rec remove_assoc a ~eq = function 36 | | [] -> [] 37 | | ((k, _) as pair) :: xs -> 38 | if eq a k then xs else pair :: remove_assoc a ~eq xs 39 | end 40 | 41 | module ListLabels = struct 42 | include ListLabels 43 | 44 | let mem a ~eq ~set = List.mem a ~eq set 45 | let assoc a ~eq xs = List.assoc a ~eq xs 46 | let assoc_opt a ~eq xs = List.assoc_opt a ~eq xs 47 | let mem_assoc a ~eq ~map = List.mem_assoc a ~eq map 48 | let remove_assoc a ~eq xs = List.remove_assoc a ~eq xs 49 | end 50 | 51 | module StdLabels = struct 52 | include (StdLabels : 53 | module type of StdLabels 54 | with module List := StdLabels.List 55 | ) 56 | 57 | module List = ListLabels 58 | end 59 | 60 | #if OCAML_VERSION < (5, 0, 0) 61 | module Pervasives = struct 62 | include Pervasives 63 | include Int 64 | end 65 | #endif 66 | 67 | include (Stdlib : 68 | module type of Stdlib 69 | with module List := Stdlib.List 70 | and module ListLabels := Stdlib.ListLabels 71 | and module StdLabels := Stdlib.StdLabels 72 | #if OCAML_VERSION < (5, 0, 0) 73 | and module Pervasives := Stdlib.Pervasives 74 | #endif 75 | and module Int := Stdlib.Int 76 | ) 77 | 78 | include Int 79 | module Int = Stdlib.Int 80 | end 81 | 82 | include Stdlib 83 | end 84 | -------------------------------------------------------------------------------- /src/monomorphic.mli: -------------------------------------------------------------------------------- 1 | (* Copyright (c) 2013-2017 Kate . *) 2 | (* See the LICENSE file at the top-level directory. *) 3 | 4 | [@@@ocaml.alert "-deprecated"] 5 | 6 | (** Shadow with specialised functions using [Ty.t] *) 7 | module Make (Ty : sig type t end) : sig 8 | external (=) : Ty.t -> Ty.t -> bool = "%equal" 9 | external (<>) : Ty.t -> Ty.t -> bool = "%notequal" 10 | external (<) : Ty.t -> Ty.t -> bool = "%lessthan" 11 | external (>) : Ty.t -> Ty.t -> bool = "%greaterthan" 12 | external (<=) : Ty.t -> Ty.t -> bool = "%lessequal" 13 | external (>=) : Ty.t -> Ty.t -> bool = "%greaterequal" 14 | external compare : Ty.t -> Ty.t -> int = "%compare" 15 | val min : Ty.t -> Ty.t -> Ty.t 16 | val max : Ty.t -> Ty.t -> Ty.t 17 | end 18 | 19 | (** Almost complete removal of the functions by shadowing *) 20 | module None : module type of Make(struct type t = unit end) 21 | 22 | (** Specialize functions with [int] *) 23 | module Int : module type of Make(struct type t = int end) 24 | 25 | (** Specialize functions with [bool] *) 26 | module Bool : module type of Make(struct type t = bool end) 27 | 28 | (** Specialize functions with [float] *) 29 | module Float : module type of Make(struct type t = float end) 30 | 31 | (** Specialize functions with [string] *) 32 | module String : module type of Make(struct type t = string end) 33 | 34 | module Stdlib : sig 35 | module Stdlib : sig 36 | module List : sig 37 | include module type of List 38 | 39 | val mem : 'a -> eq:('a -> 'a -> bool) -> 'a list -> bool 40 | val assoc : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> 'a 41 | val assoc_opt : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> 'a option 42 | val mem_assoc : 'k -> eq:('k -> 'k -> bool) -> ('k * _) list -> bool 43 | val remove_assoc : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> ('k * 'a) list 44 | end 45 | 46 | module ListLabels : sig 47 | include module type of ListLabels 48 | 49 | val mem : 'a -> eq:('a -> 'a -> bool) -> set:'a list -> bool 50 | val assoc : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> 'a 51 | val assoc_opt : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> 'a option 52 | val mem_assoc : 'k -> eq:('k -> 'k -> bool) -> map:('k * _) list -> bool 53 | val remove_assoc : 'k -> eq:('k -> 'k -> bool) -> ('k * 'a) list -> ('k * 'a) list 54 | end 55 | 56 | module StdLabels : sig 57 | include module type of (StdLabels : 58 | module type of StdLabels 59 | with module List := StdLabels.List 60 | ) 61 | 62 | module List = ListLabels 63 | end 64 | 65 | #if OCAML_VERSION < (5, 0, 0) 66 | module Pervasives : sig 67 | include module type of Pervasives 68 | include module type of Int 69 | end 70 | #endif 71 | 72 | include module type of (Stdlib : 73 | module type of Stdlib 74 | with module List := Stdlib.List 75 | and module ListLabels := Stdlib.ListLabels 76 | and module StdLabels := Stdlib.StdLabels 77 | #if OCAML_VERSION < (5, 0, 0) 78 | and module Pervasives := Stdlib.Pervasives 79 | #endif 80 | and module Int := Stdlib.Int 81 | ) 82 | 83 | include module type of Int 84 | module Int = Stdlib.Int 85 | end 86 | 87 | include module type of Stdlib 88 | end 89 | -------------------------------------------------------------------------------- /test/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name test) 3 | (libraries monomorphic)) 4 | -------------------------------------------------------------------------------- /test/test.ml: -------------------------------------------------------------------------------- 1 | [@@@ocaml.warning "-32"] 2 | 3 | module CheckExternal : sig 4 | external (=) : int -> int -> bool = "%equal" 5 | external (<>) : int -> int -> bool = "%notequal" 6 | external (<) : int -> int -> bool = "%lessthan" 7 | external (>) : int -> int -> bool = "%greaterthan" 8 | external (<=) : int -> int -> bool = "%lessequal" 9 | external (>=) : int -> int -> bool = "%greaterequal" 10 | external compare : int -> int -> int = "%compare" 11 | val min : int -> int -> int (* TODO: Add some kind of tests to ensure those functions *) 12 | val max : int -> int -> int (* stay in sync with the standard library in terms of 13 | whether they are externals or not *) 14 | end = Monomorphic.Stdlib 15 | 16 | module CheckTypes : sig 17 | module type T = sig 18 | val (=) : int -> int -> bool 19 | val (<>) : int -> int -> bool 20 | val (<) : int -> int -> bool 21 | val (>) : int -> int -> bool 22 | val (<=) : int -> int -> bool 23 | val (>=) : int -> int -> bool 24 | val compare : int -> int -> int 25 | val min : int -> int -> int 26 | val max : int -> int -> int 27 | end 28 | end = struct 29 | module type T = module type of struct 30 | open Monomorphic.Stdlib 31 | 32 | let (=) = (=) 33 | let (<>) = (<>) 34 | let (<) = (<) 35 | let (>) = (>) 36 | let (<=) = (<=) 37 | let (>=) = (>=) 38 | let compare = compare 39 | let min = min 40 | let max = max 41 | end 42 | end 43 | --------------------------------------------------------------------------------