How do I hide a constructor? - ocaml

I'm trying to build a type LazyList but hide the definition of LazyList.t. I've got the following files:
LazyList.ml
type 'a t =
| Cell of ('a * 'a t) option Lazy.t
;;
let rec from_list l = ...;;
let rec from_string s = ...;;
let rec from_in_channel c = ...;;
let rec to_list l = ...;;
LazyList.mli
type 'a t;;
val from_list : 'a list -> 'a t;
val from_string : string -> char t;
val from_in_channel : in_channel -> char t;
val to_list : 'a t -> 'a list;
When I run ocamlc LazyList.mli I get the following error:
File "LazyList.mli", line 1, characters 9-10:
Error: Syntax error
What gives? Do I need to expose the constructor if I'm going to be writing all of the methods I need in LazyList.ml?

This is only a syntax error. Semicolons cannot appear in mli file. Also you really do not need to use this ugly double semicolons in ml file, although it is not an error.

Related

Is there an universal printer in OCaml that detect the type?

I want to print a list with different element in it (for educational purpose)
I have read a tutorial that explain how to store different type in list.
type _ list =
[] : unit list
| ( :: ) : 'b * 'a list -> ('b ->'a) list;;
1 :: "e" :: 'r' :: [];; (* this is allowed *)
how I can do something like this pseudo-code:
match typeof(my_expr) with
int -> print_int
| string -> print_string
we will have "1,e,r" printed.
Some solutions i have searched
Change my type in text and printing it
Use a different type definition maybe ('a, 'b) list ?
I ask this because the OCaml toplevel know the type of every variable and show always the type in the right format: can I call this printer ?
Is there a solution only for toplevel that we can install with the #install_printer ?
I know that compiler discard type's info after the type checking pass.
The printer of the toplevel should work fine:
[1; "one"; 1.];;
- : (int -> string -> float -> unit) list =
(::) (1, (::) ("one", (::) (1., [])))
(The unoptimal printing is an unfortunate consequence of ensuring that values printed by the toplevel can be copy-pasted back to the top-level and yields the same value)
But this is only possible outside of the language itself: the toplevel printers can inspect the typing environment which is purposefully not possible in the language itself. Indeed functions like typeof would break parametricity. There is thus no universal printer function in OCaml (without looking at the internal memory representation) and no universal heterogeneous list printer.
If you want to print an heterogeneous list, there are three possible paths:
print a specific type of the heterogeneous list
let print_concrete ppf (x::y::z::rest) = Format.fprintf ppf "%f %f %f" x y z
(Contrary to appearance, this function is total: its type makes it impossible to use on lists with fewer than three elements)
Use heterogeneous lists that always pack a printing function along its main value
type 'a printer = Format.formatter -> 'a -> unit
type _ showable_list =
| [] : unit showable_list
| (::):
('a * 'a printer) * 'b showable_list
-> ('a -> 'b) showable_list
let rec print: type a. a showable_list printer =
fun ppf l -> match l with
| [] -> ()
| (a,printer) :: rest -> Format.fprintf ppf "%a# %a" printer a print rest
provide a matching heterogeneous list of printing functions
type 'a plist =
| []: unit plist
| (::): 'a printer * 'b plist -> ('a -> 'b) plist
let rec print: type l. l plist -> l list printer = fun printers ppf values ->
match printers, values with
| [], [] -> ()
| p :: prest, a :: rest -> Format.fprintf ppf "%a# %a" p a (print prest) rest
The fact that you often need to specialize the heterogeneous list type may make it worthwhile to introduce a functor for generating them:
module Hlist(Specialization: sig type 'a t end) = struct
open Specialization
type 'a list =
| []: unit list
| (::): 'a t * 'b list -> ('a -> 'b) list
end
then the previous specialized type can be constructed with
module Showable_list = Hlist(struct type 'a t = 'a * 'a printer end)
module Printer_list = Hlist (struct type 'a t = 'a printer end)

Ocaml : Function with 'a option error

I have this simple function which drives me crazy:
it should be a function of this type :
myfunction : (int * int list) list -> int -> int
For each tuples of the first argument :
When the second argument matches the first element of the tuple then the function return the last element of the list in the tuple.
If no matches it should return -1.
let rec myfunction alist anum =
let last_e l =
let len = List.length l in
List.nth l (len - 1) in
match alist with
| [] -> -1
| (n , ln) :: q -> if n = anum then last_e ln
else myfunction q anum
But my function does not work and I have this error message in utop:
Error: This expression has type 'a option but an expression was expected of type int
I don't know where the "option" type comes from.
This can happen if you are using some OCaml toplevel (e.g. utop) and you have these lines in your .ocamlinit file
#require "core.top" ;;
open Core.Std ;;
This enables the Core libraries, where List.nth has type:
μ> List.nth;;
- : 'a list -> int -> 'a option = <fun>
instead of standard OCaml's List.nth : 'a list -> int -> 'a.
So, when you fire up your toplevel and say:
μ> #use "myfunction.ml";;
you get the same error you cited in the question.
By the way, if you'd like to keep using Core, there is a List.last function.

Java GuardTypes analogy for OCaml

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" *)

Value not polymorphic enough

Here's a minimal example out of my code demonstrating the problem:
module Substring = struct
type t = {
base: string;
pos: int;
len: int
}
end
module Parser = struct
type 'a t = Substring.t -> ('a * Substring.t) option
let return x s = Some (x, s)
end
type (_, _) t =
| TryParse : unit Parser.t -> ('a, 'a) t
| Parse : 'b Parser.t -> ('a, 'b -> 'a) t
| Concat : ('b, 'c) t * ('a, 'b) t -> ('a, 'c) t
let p = Parse (Parser.return "xxx")
My problem is that I want val p : ('a, string -> 'a) t to be polymorphic and yet OCaml makes 'a weak: val p : ('_a, string -> '_a). I'm pretty sure I'm being bitten by the value restriction here and I'm not quite sure how to get around it.
Yes, this is the value restriction. You need to eta-expand the problematic definition, like this:
let p = Parse (fun x -> Parser.return "xxx" x)
Annoying, isn't it?
If you want a binding to be polymorphic then you usually have to ensure that it is a "syntactic value". An expression containing a partial application doesn't qualify (because in general partial applications may have an effect), but a (fun ...) is fine.

OCaml: the variant type unit has no constructor ::

I'm trying to implement sets through lists.. This is the code with the implementation (I omitted the interface):
module MySet : Set =
struct
type 'a set = 'a list
let empty : 'a set = []
let add (x: 'a) (s: 'a set) : 'a set =
if not(List.mem x s) then x::s
let remove (x: 'a) (s: 'a set) : 'a set =
let rec foo s res =
match s with
| [] -> List.rev res
| y::ys when y = x -> foo ys res
| y::ys -> foo ys (y::res)
in foo s []
let list_to_set (l: 'a list) : 'a set =
let rec foo l res =
match l with
| [] -> List.rev res
| x::xs when member x xs -> foo xs res
| x::xs -> foo xs (x::res)
in foo l []
let member (x: 'a) (s: 'set) : bool =
List.mem x s
let elements (s: 'a set) : 'a list =
let rec foo s res =
match s with
| [] -> List.rev res
| x::xs -> foo xs (x::res)
in foo s []
end;;
This is the error I get
Characters 162-164:
if not(List.mem x s) then x::s
^^
Error: The variant type unit has no constructor ::
I can't understand the error
It's a very confusing message that we got since 4.01 that stems from the fact that you have no else branch and that () is a valid constructor for unit.
Since you have no else branch the whole if must type to unit and thus the then branch aswell and it tries to unify the expression in the then branch with a value of type unit and detects that :: is not a constructor for values of type unit.
What you wanted to write is:
if not (List.mem x s) then x :: s else s
Without an else branch your add function needs to type to 'a -> 'a set -> unit
The strange error message is being bug tracked in OCaml's issue tracker, see PR 6173.