I would like to make my code generic over strings and arrays (any indexable type really) using the following signature:
module type Indexable = sig
type 'a t
val get : int -> 'a t -> 'a
end
module MyCode (I : Indexable) = struct ... end
But of course I cannot apply my signature to strings as follows:
module StrMyCode = MyCode(struct
type 'a t = string
let get i a = a.[i]
end)
Is there any way to fix this issue? Or perhaps a different aprroach? I know I can use arrays of characters in the worst case but I'd rather save my code from ugly casts and this is something that was on my mind before so I'd like to get a clear answer for this.
GADT can be used with the functorized approach:
module type Indexable = sig
type 'a t
val get: int -> 'a t -> 'a
end
module MyCode(I:Indexable) = struct
let head x = I.get 0 x
end
Arrays can of course be made Indexable trivially:
module IndexableArray = struct
type 'a t = 'a array
let get i x = x.(i)
end
For string, you can just use a GADT with a single constructor. Note however, that you have to put some type annotation for get in order to force the polymorphic type (otherwise, the inferred type is int -> char t -> char):
module IndexableString = struct
type 'a t = String: string -> char t
let of_string s = String s
let get: type a. int -> a t -> a =
fun i s -> match s with String s -> s.[i]
end
Here is something I made using GADTs. I'm just wrapping my head around them, so there may be something a little wrong here. But it seems to work as far as I can see (with OCaml 4):
type _ indexable =
| A : 'a array -> 'a indexable
| C : string -> char indexable
let index (type s) (x: s indexable) i : s =
match x with
| A a -> a.(i)
| C s -> s.[i]
let main () =
let x = A [| 1; 2 |] in
let y = C "abc" in
Printf.printf "%d\n" (index x 0);
Printf.printf "%c\n" (index y 1)
If I load into the toplevel, I get this:
val index : 'a indexable -> int -> 'a = <fun>
val main : unit -> unit = <fun>
# main ();;
1
b
- : unit = ()
#
This might not be as general as what you're looking for.
If you declare the element type of the indexable as a separate type, you can do something like this:
module type Indexable = sig
type t
type elt
val get : int -> t -> elt
end
module IndexableString : Indexable = struct
type t = string
type elt = char
let get i a = a.[i]
end
module MyCode (I : Indexable) = struct
(* My code implementation *)
end
module StrMyCode = MyCode(IndexableString)
For arrays, you can do more or less the same:
module ArrayIndexable = struct
type elt = char
type t = char array
let get i a = a.(i)
end
Now, if you wish to retain some flexibility with arrays, you may change the above into a functor:
module ArrayIndexable (E : sig type e end) : Indexable with type elt = E.e =
struct
type elt = e
type t = elt array
let get i a = a.(i)
end
It is more verbose than the polymorphic version you are looking for, but it let you encode both "indexable" types uniformly.
Related
I would like to constrain a type variable to allow only polymorphic variant types, such that I could use the variable to construct other polymorphic variant types in a signature:
type 'a t
val f : 'a t -> [`Tag | 'a] t
Is there a way to accomplish this in OCaml? Perhaps using classes/objects instead? A naive attempt failed to compile:
type 'a t = { dummy: int } constraint 'a = [>]
let f : 'a t -> ['a | `Tag] t = fun _ -> { dummy = 0 }
^^
The type [> ] does not expand to a polymorphic variant type
Reason for the question:
I want to use the type signature to reflect capabilities of a t statically, to enforce that a t without a given capability can never be used inappropriately.
val do_something_cool : [<`Super_power] t -> unit
val do_something_else : [<`Super_power|`Extra_super_power] t -> unit
val enhance : 'a t -> ['a | `Super_power] t
val plain_t : [`Empty] t
let () = plain_t |> do_something_cool (* fails *)
let () = plain_t |> enhance |> do_something_cool (* succeeds *)
let () = plain_t |> enhance |> do_something_else (* succeeds *)
Obviously there are other ways to achieve this compile-time safety. For example, enhance could just return a [`Super_power] t that could be used in place of plain_t where required. However, I'm really curious whether the first way could succeed. I am writing a DSL which would be a lot more concise if all the capabilities of t could be reflected in its type.
The short answer is no: it is only possible to inline type declarations, not type variables. In other words, this is fine:
type on = [`On]
type off = [`Off]
type any = [ on | off ]
let f: [< any ] -> _ = fun _ -> ()
but not this
let merge: 'a -> 'b -> [ 'a | 'b ] = ...
However, if you only have a closed set of independent capabilities, it might work to switch to an object phantom type where each capacity correspond to a field and each field can be either on or off. For instance,
type +'a t constraint 'a = < super: [< any ]; extra: [< any ]>
Then consumer functions that only require a conjunction of capabilities are relatively easy to write:
val do_something_cool : < super:on; ..> t -> unit
val do_something_extra : < extra:on; ..> t -> unit
val do_something_super_but_not_extra: <super:on; extra:off; .. > t -> unit
but switching a capability on or off is more complex and fixes the set of capabilities:
val enhance : < super: _; extra: 'es > t -> < super: on; extra:'es > t
Beyond those limitations, everything works as expected. For instance, if I have a variable x
val x: <super: off; extra:on > t
This works:
let () = do_something_extra x
whereas
let () = do_something_cool x
fails and finally
let () =
let x = enhance x in
do_something_cool x; do_something_extra x
works fine too.
The main issue is thus writing the enable function. One trick that may help is to
write helper type to manipulate more easily a subset of capabilities.
For instance, if I have a complex type:
type 'a s
constraint 'a = < a: [< any]; b:[< any]; c: [< any ]; d: [< any] >
I can use the following type:
type ('a, 'others) a = < a:'a; b:'b; c:'c; d: 'd>
constraint 'others = 'b * 'c * 'd
to select the capability a, and thus write
val enable_a: (_,'rest) a s -> (on, 'rest) a s
without having to explicit the three type variables hidden in 'rest.
How do you do, Stackoverflow!
In Java practice there are some issues concerning partially defined functions. Sometimes it's convinient to separate an error handling from the calculation itself. We may utilize an approach called "Guard types" or "Guard decorators".
Consider the simple synthetic example: to guard the null reference. This can be done with the aid of the next class
public class NonNull<T> {
public take() {
return null != this.ref ? this.ref : throw new ExcptionOfMine("message");
}
public NotNull(T ref_) {
this.ref = ref_;
}
private T ref;
}
The question is:
Is there a way to implement the same "Guard type" in OCaml without touching its object model? I believe for the OCaml as the functional programming language to possess enough abstraction methods without objec-oriented technics.
You can use an abstract type to get the same effect. OCaml has no problem with null pointers. So say instead you want to represent a nonempty list in the same way as above. I.e., you want to be able to create values that are empty, but only complain when the person tries to access the value.
module G :
sig type 'a t
val make : 'a list -> 'a t
val take : 'a t -> 'a list
end =
struct
type 'a t = 'a list
let make x = x
let take x = if x = [] then raise (Invalid_argument "take") else x
end
Here's how it looks when you use the module:
$ ocaml
OCaml version 4.02.1
# #use "m.ml";;
module G :
sig type 'a t val make : 'a list -> 'a t val take : 'a t -> 'a list end
# let x = G.make [4];;
val x : int G.t = <abstr>
# G.take x;;
- : int list = [4]
# let y = G.make [];;
val y : '_a G.t = <abstr>
# G.take y;;
Exception: Invalid_argument "take".
There's a concept of Optional types, on which you can effectively pattern match. Example:
let optional = Some 20
let value =
match optional with
| Some v -> v
| None -> 0
You can use simple closures
let guard_list v =
fun () ->
if v = [] then failwith "Empty list"
else v
let () =
let a = guard_list [1;2;3] in
let b = guard_list [] in
print_int (List.length (a ())); (* prints 3 *)
print_int (List.length (b ())) (* throws Failure "Empty list" *)
or lazy values
let guard_string v = lazy begin
if v = "" then failwith "Empty string"
else v
end
let () =
let a = guard_string "Foo" in
let b = guard_string "" in
print_endline (Lazy.force a); (* prints "Foo" *)
print_endline (Lazy.force b) (* throws Failure "Empty string" *)
I am trying to parametrise a functor using a type parameter in a declaration. As an example, suppose I have the following GADT declaration:
type _ basic =
| String : string -> string basic
| Integer : int -> int basic
I want to use Map.Make to construct maps using the above type as the key type. Since I cannot leave a type variable free in type t = 'a basic, I have a functor to make 'a basic into an OrderedType:
module OrderedBasic(Type : sig type tag end) :
(Map.OrderedType with type t = Type.tag basic) =
struct
type t = Type.tag basic
let compare : type a. a basic -> a basic -> int = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> String.compare s1 s2
| Integer i1, Integer i2 -> compare i1 i2
end
I can create the maps I wanted:
module OrderedBasicString = OrderedBasic(struct type tag = string end)
module BasicStringMap = Map.Make(OrderedBasicString)
and name the map type:
type 'v string_map = 'v BasicStringMap.t
However, what I would like to do is to parametrise the type of maps by the type parameter of basic, i.e., something like:
type ('k, 'v) basic_map = 'v Map.Make(OrderedBasic(struct type tag = 'k end)).t
But this doesn't seem to be allowed: I get a syntax error at the inline struct definition. Ultimately, I want to embed maps, which can have any of the above basic key types, in another GADT as in:
type _ data =
Map : 'a data Map.Make(OrderedBasic(struct type tag = 'b end)).t -> 'c data
Is there a way to make this work?
The problem is that Map is defined over key types of fixed arity, and that arity is zero.
It's easy if the functor you are using allows the arity you want:
type _ basic =
| String : string -> string basic
| Integer : int -> int basic
module type INDEXED = sig
type 'a t
val equal : 'a t -> 'a t -> bool
end
module MakeAlist (Elt : INDEXED) = struct
type ('i, 'v) t = Nil | Cons of 'i Elt.t * 'v * ('i, 'v) t
let rec find elt = function
| Nil -> None
| Cons (x, v, xs) ->
if Elt.equal elt x then Some v
else find elt xs
(* etc *)
end
module BasicAlist = MakeAlist (struct
type 'a t = 'a basic
let equal : type a . a basic -> a basic -> bool = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> s1 = s2
| Integer i1, Integer i2 -> i1 = i2
end)
type _ data = Map : ('a data, 'b) BasicAlist.t -> 'c data
I won't go as far as suggesting that you reimplement Map with the arity that you want, although that would solve your problem - there might be some trick I'm not aware of that would let you reuse Map.
You have to use a map that is polymorphic in the type of the key such as the map from core.
open Core.Std
module Basic = struct
type 'a t =
| String : string -> string t
| Int : int -> int t
let sexp_of_t : type a. a t -> Sexp.t = function
| String s -> String.sexp_of_t s
| Int i -> Int.sexp_of_t i
let compare : type a. a t -> a t -> int = fun b1 b2 ->
match b1, b2 with
| String s1, String s2 -> String.compare s1 s2
| Int i1, Int i2 -> compare i1 i2
end
module Cmp = Comparator.Make1(Basic)
type _ data =
Map : ('a Basic.t, 'b, Cmp.comparator_witness) Map.t -> 'c data
I've get the follow code about the functors in OCaml:
type comparison = Less | Equal | Greater;;
module type ORDERED_TYPE =
sig
type t
val compare: t -> t -> comparison
end
;;
module Set =
functor (Elt: ORDERED_TYPE) ->
struct
type element = Elt.t
type set = element list
let empty = []
let rec add x s =
match s with
| [] -> [x]
| hd :: tl ->
match Elt.compare x hd with
| Equal -> s
| Less -> x :: s
| Greater -> hd :: add x tl
let rec member x s =
match s with
| [] -> false
| hd :: tl ->
match Elt.compare x hd with
| Equal -> true
| Less -> false
| Greater -> member x tl
end
;;
module OrderedString : ORDERED_TYPE =
struct
type t = string
let compare x y =
if x = y then Equal
else if x < y then Less
else Greater
end
;;
module StringSet = Set(OrderedString);;
let out = StringSet.member "foo" (StringSet.add "foo" StringSet.empty);; (*compile error, where "foo" is expected OrderedString.t but actually is string*)
The above error can be avoided by eliminating the : ORDERED_TYPE in module OrderedString : ORDERED_TYPE =
Just can't understand why.
Analogously, if there is any type in a module like
module A = struct type t = string end;;
How can I specify a string value as the type A.t but not an actual string
Thanks.
You can look at how it is done in the standard library : set.mli.
The signature of the functor is
module Make (Ord : OrderedType) : S with type elt = Ord.t
the with type elt = Ord.t part indicates that the elt type is not abstract.
As mentioned by Tomash, you're lacking a type constraint, but not in the functor signature (there isn't any in your code in fact), but in the argument you're giving to it. Basically, when you write
module OrderedString : ORDERED_TYPE = struct ... end
the definition of the type t in OrderedString will be abstracted away, since t is an abstract type in the ORDERED_TYPE signature. What you want here is to say that OrderedString is indeed an implementation of ORDERED_TYPE, but with a known type t. This is exactly what you'll get with
module OrderedString: ORDERED_TYPE with type t = string = struct ... end
Is it really true that OCaml doesn't have a function which converts from a list to a set?
If that is the case, is it possible to make a generic function list_to_set? I've tried to make a polymorphic set without luck.
Fundamental problem: Lists can contain elements of any types. Sets (assuming you mean the Set module of the standard library), in contrary, rely on a element comparison operation to remain balanced trees. You cannot hope to convert a t list to a set if you don't have a comparison operation on t.
Practical problem: the Set module of the standard library is functorized: it takes as input a module representing your element type and its comparison operation, and produces as output a module representing the set. Making this work with the simple parametric polymoprhism of lists is a bit sport.
To do this, the easiest way is to wrap your set_of_list function in a functor, so that it is itself parametrized by a comparison function.
module SetOfList (E : Set.OrderedType) = struct
module S = Set.Make(E)
let set_of_list li =
List.fold_left (fun set elem -> S.add elem set) S.empty li
end
You can then use for example with the String module, which provides a suitable compare function.
module SoL = SetOfList(String);;
SoL.S.cardinal (SoL.set_of_list ["foo"; "bar"; "baz"]);; (* returns 3 *)
It is also possible to use different implementation of sets which are non-functorized, such as Batteries and Extlib 'PSet' implementation (documentation). The functorized design is advised because it has better typing guarantees -- you can't mix sets of the same element type using different comparison operations.
NB: of course, if you already have a given set module, instantiated form the Set.Make functor, you don't need all this; but you conversion function won't be polymorphic. For example assume I have the StringSet module defined in my code:
module StringSet = Set.Make(String)
Then I can write stringset_of_list easily, using StringSet.add and StringSet.empty:
let stringset_of_list li =
List.fold_left (fun set elem -> StringSet.add elem set) StringSet.empty li
In case you're not familiar with folds, here is a direct, non tail-recursive recursive version:
let rec stringset_of_list = function
| [] -> StringSet.empty
| hd::tl -> StringSet.add hd (stringset_of_list tl)
Ocaml 3.12 has extensions (7,13 Explicit naming of type variables and 7,14 First-class modules) that make it possible to instantiate and pass around modules for polymorphic values.
In this example, the make_set function returns a Set module for a given comparison function and the build_demo function constructs a set given a module and a list of values:
let make_set (type a) compare =
let module Ord = struct
type t = a
let compare = compare
end
in (module Set.Make (Ord) : Set.S with type elt = a)
let build_demo (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
let set = List.fold_right S.add xs S.empty in
Printf.printf "%b\n" (S.cardinal set = List.length xs)
let demo (type a) xs = build_demo (make_set compare) xs
let _ = begin demo ['a', 'b', 'c']; demo [1, 2, 3]; end
This doesn't fully solve the problem, though, because the compiler doesn't allow the return value to have a type that depends on the module argument:
let list_to_set (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
List.fold_right S.add xs S.empty
Error: This `let module' expression has type S.t
In this type, the locally bound module name S escapes its scope
A possible work-around is to return a collection of functions that operate on the hidden set value:
let list_to_add_mem_set (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
let set = ref (List.fold_right S.add xs S.empty) in
let add x = set := S.add x !set in
let mem x = S.mem x !set in
(add, mem)
If you don't mind a very crude approach, you can use the polymorphic hash table interface. A hash table with an element type of unit is just a set.
# let set_of_list l =
let res = Hashtbl.create (List.length l)
in let () = List.iter (fun x -> Hashtbl.add res x ()) l
in res;;
val set_of_list : 'a list -> ('a, unit) Hashtbl.t = <fun>
# let a = set_of_list [3;5;7];;
val a : (int, unit) Hashtbl.t = <abstr>
# let b = set_of_list ["yes";"no"];;
val b : (string, unit) Hashtbl.t = <abstr>
# Hashtbl.mem a 5;;
- : bool = true
# Hashtbl.mem a 6;;
- : bool = false
# Hashtbl.mem b "no";;
- : bool = true
If you just need to test membership, this might be good enough. If you wanted other set operations (like union and intersection) this isn't a very nice solution. And it's definitely not very elegant from a typing standpoint.
Just extend the original type, as shown in
http://www.ffconsultancy.com/ocaml/benefits/modules.html
for the List module:
module StringSet = Set.Make (* define basic type *)
(struct
type t = string
let compare = Pervasives.compare
end)
module StringSet = struct (* extend type with more operations *)
include StringSet
let of_list l =
List.fold_left
(fun s e -> StringSet.add e s)
StringSet.empty l
end;;
Using the core library you could do something like:
let list_to_set l =
List.fold l ~init:(Set.empty ~comparator:Comparator.Poly.comparator)
~f:Set.add |> Set.to_list
So for example:
list_to_set [4;6;3;6;3;4;3;8;2]
-> [2; 3; 4; 6; 8]
Or:
list_to_set ["d";"g";"d";"a"]
-> ["a"; "d"; "g"]