F# Analysis of Option Statement - recursion

I have extracted the following line from a function that's starts like so (textbook example incomplete):
let rec unify (exp1:exp) (exp2:exp) (k:(subst -> subst)) (sub:subst) =
match checkmap exp1 sub,checkmap exp2 sub with
| Var a,Var b when a = b -> k sub
| Var a,Var b -> k (safeInput<|||((safeInput<|||(sub,a,Var(b))),b,Var(a)))
Line:
Var a,Var b -> k (safeInput<|||((safeInput<|||(sub,a,Var(b))),b,Var(a)))
The safeInput reference 'safely' inputs a type into a Map structure... I am just wondering what the operators here are actually doing? Also, if there is a more intuitive way to structure the above line?

If you type
(<|||);;
into F# Interactive, you get its signature:
val it : (('a -> 'b -> 'c -> 'd) -> 'a * 'b * 'c -> 'd) = <fun:it#1>
Its definition is something like
let inline (<|||) f (a, b, c) = f a b c
so the last expression can be rewritten to
k (safeInput (safeInput sub a (Var b)) b (Var a))
To improve the function, you can also:
Create let bindings to hold immediate values
Reuse exp1 and exp2 instead creating the same values
e.g.
let rec unify (exp1 : exp) (exp2 : exp) (k : subst -> subst) (sub : subst) =
match checkmap exp1 sub,checkmap exp2 sub with
| Var a, Var b when a = b -> k sub
| Var a, Var b ->
let sub' = safeInput sub a exp2
k (safeInput sub' b exp1)

The <||| operator simply passes the arguments on the right (provided as a tuple) to the function on the left, so the line means the same as:
k (safeInput (safeInput sub a (Var b)) b (Var a))
Or, if you want to split the line into two to make it more readable:
let sub' = safeInput sub a (Var b)
k (safeInput sub' b (Var a))
I don't know the book that uses this, but I suppose the idea is to add mapping from variable 'a' to variable 'b' and another mapping back from variable 'b' to variable 'a'.

Related

Does a non terminating function have a type?

Consider for example let f x = f x in f 1. Is its signature defined?
If so, what is it?
One could argue, that OCaml doesn't know about the fact that it's not terminating and that its type is simply inferred as 'a. Is that correct?
let a b = let rec f x = f x in f 1;;
is for example val a : 'a -> 'b eventhough it is very clear, that when a is applied, there won't be a 'b
Then requirement for a sound type system when you have type(E) = T is that if E evaluates to some value v, then v is a value that belongs to type T. A type is meaningful when the expression gives a value, and exceptions and infinite loops do not.
The type checker however is total, and gives a type for all expression, even if it is just a free type variable.
Here the return type is left unbound, and is printed as 'a.
# let f x = if x then (failwith "A") else (failwith "B");;
val f : bool -> 'a = <fun>
Here the return type of the then branch is unified with the type of the else branch:
# let f x = if x then (failwith "A") else 5;;
val f : bool -> int = <fun>
#
One way to read function types like unit -> 'a is to remember that the
type variable 'a encompasses empty types.
For example, if I have a function f
let rec f:'a. _ -> 'a = fun () -> f ()
and an empty type
type empty = |
(* using 4.07 empty variants *)
(* or *)
type (_,_) eq = Refl: ('a,'a) eq
type empty = (float,int) eq
then I can restrict the type of f to unit -> empty:
let g: unit -> empty = f
Moreover, the more general type of f can be useful in presence of branches.
For instance, I could define a return that raises an exception in order
to exit early from a for-loop:
let search pred n =
let exception Return of int in
let return: 'a. int -> 'a = fun n -> raise (Return n) in
try
for i = 0 to n do
if pred i then return i
done;
None
with Return n -> Some n
Here, the polymorphic type of return makes it possible to use it in a context
where unit was expected.

Error: This expression has type int but an expression was expected of type 'a option

Here is my code:
let rec size = function
| [] -> 0
| t::q -> 1 + size q
let rec n k v lst = match lst with
| [] -> None
| t::q when (v - size q) = k -> t
| _::q -> n k v q
let () = print_int (n (3) (5) ([ 1 ; 2; 3; 4; 5 ]) )
It's saying the following:
File "main.ml", line 10, characters 33-34:
Error: This expression has type int but an expression was expected of type
'a option
I don't understand what it means.
I am trying to print the nth element of a list. I mean print_int is waiting for an int and k, v are integers.
The first case of your function n returns None whose type is 'a option.
You then proceed to return t, therefore the compiler deduce t must also be of type 'a option.
You should use the constructor Some when returning t:
let rec n k v lst = match lst with
|[] -> None
|t::q when (v - size q) = k -> Some t
|_::q -> n k v q
You won't however be able to use it with print_int right away, you will have to unpack the option type in the following way:
let () = match (n (3) (5) ([ 1 ; 2; 3; 4; 5 ]) ) with
| Some v -> print_int v
| None -> ()
Your function n has type int -> int -> 'a option list -> 'a option because in the first case
| [] -> None
you're returning None that is a value of type 'a option, and on the second case
|t::q when (v - size q) = k -> t
you're returning an element of the list. Since a function can have only one return type, the type inference algorithm unifies the type of the list elements with the option type, thus requiring the input list elements to have type 'a option
The print_int function accepts values of type int, but you're passing something that is 'a option that is not an int. Moreover, if you will remove print_int then the following expression won't type either:
let _ = n 3 5 [1;2;3;4;5]
because your n function accepts a list of options, not a list of integers, e.g.,
let _ = n 3 4 [Some 1; Some 2; None; None]

Recursion in F#, expected type int but got type "int list -> int"

I'm new to F# and want to implement a least common multiple function of a list by doing it recursively, e.g. lcm(a,b,c) = lcm(a, lcm(b,c)), where lcm of two elements is calculated from the gcd.
I have the following code. I try to match the input of the lcm function with a list of two elements, and otherwise a general list, which I split up into its first element and the remaining part. The part "lcm (tail)" gives a compiler error. It says it was expected to have type "int" but has type "int list -> int". It looks like it says that the expression "lcm tail" is itself a function, which I don't understand. Why is it not an int?
let rec gcd a b =
if b = 0
then abs a
else gcd b (a % b)
let lcmSimple a b = a*b/(gcd a b)
let rec lcm list = function
| [a;b] -> lcmSimple a b
| head::tail -> lcmSimple (head) (lcm (tail))
Best regards.
When defining the function as let f = function | ..., the argument to the function is implicit, as it is interpreted as let f x = match x with | ....
Thus let rec lcm list = function |... is a function of two variables, which are list and the implicit variable. This is why the compiler claims that lcm tail is a function - only one variable has been passed, where it expected two. A better version of the code is
let rec gcd a b =
if b = 0
then abs a
else gcd b (a % b)
let lcmSimple a b = a*b/(gcd a b)
let rec lcm = function
| [a;b] -> lcmSimple a b
| head::tail -> lcmSimple (head) (lcm (tail))
| [] -> 1
where the last case has been included to complete the pattern.

OCaml Understanding Functions and Partial Applications

I am writing a form of form of transform in OCaml that takes in a function and also accepts a list to transform. I understand something is wrong with my pattern matching in terms of type-checking, as it will not compile and claims the types do not match but I am not sure what exactly is wrong with my cases.
I receive an actual declaration error underlining the name of the function when I attempt to compile.
let rec convert (fun: 'b -> 'c option) (l: 'b list) : 'c list =
begin match l with
| [] -> []
| h::tl -> if f h = Some h then h :: convert f tl
else convert f tl
end
I wrote the following test, which should pass in order to ensure the function works properly.
let test () : bool =
let f = func x -> if x > 3 then Some (x + 1) else None in
convert f [-1; 3; 4] = [5]
;; run_test "Add one" test
I am pretty confident the error is somewhere in my second pattern match.
You should provide the exact error message in the future when asking about a compilation error (as well as the position the compiler complains about).
In h :: convert f tl, convert f tl is 'c list, but h is 'b, so you can't combine them like this. Neither does f h = Some h make sense: f h is 'c option and Some h is 'b option. You probably want to match f h instead:
| h::tl -> match f h with
| Some h1 -> ...
| None -> ...

OCaml recursive modules across compilation units

I'm trying to split the following recursive modules into separate compilation units. Specifically, I'd like B to be in its own b.ml, to be able to reuse it with other A's.
module type AT = sig
type b
type t = Foo of b | Bar
val f : t -> b list
end
module type BT = sig
type a
type t = { aaa: a list; bo: t option }
val g : t -> t list
end
module rec A : (AT with type b = B.t) = struct
type b = B.t
type t = Foo of b | Bar
let f = function Foo b -> [ b ] | Bar -> []
end
and B : (BT with type a = A.t) = struct
type a = A.t
type t = { aaa: a list; bo: t option }
let g b =
let ss = List.flatten (List.map A.f b.aaa) in
match b.bo with
| Some b' -> b' :: ss
| None -> ss
end
let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;
I can't figure out how to split it across units.
The following sentence from Xavier Leroy's paper on the topic gives me hope that it's possible to encode using OCaml's module syntax: "the proposal does not support recursion between compilation units. The latter can however be encoded using separately-compiled functors, whose fix-point is taken later using the module rec construct".
I've played around with module rec but can't seem to find a way to make it type-check. The use of A's function f inside B's function g seems to cause the trouble.
(For the context, in the original code A.t is an instruction type, and B.t is a basic block type. Branch instructions reference blocks, and blocks contain lists of instructions. I'd like to reuse the basic block type and associated functions with different instruction sets.)
I think the paper is referring to something like this:
(* a.ml *)
module F (X : sig val x : 'a -> 'a end) =
struct
let y s = X.x s
end
(* b.ml *)
module F (Y : sig val y : 'a -> 'a end) =
struct
(* Can use Y.y s instead to get infinite loop. *)
let x s = Y.y |> ignore; s
end
(* c.ml *)
module rec A' : sig val y : 'a -> 'a end = A.F (B')
and B' : sig val x : 'a -> 'a end = B.F (A')
let () =
A'.y "hello" |> print_endline;
B'.x "world" |> print_endline
Running this (ocamlc a.ml b.ml c.ml && ./a.out) prints
hello
world
Obviously, the definitions of A and B I used are nonsense, but you should be able to substitute your own definitions into this pattern, as well as use named signatures instead of writing them out literally like I did.
The following seems to work, although it is rather ugly.
(* asig.mli *)
module type AT = sig
type b
type b' (* b = b' will be enforced externally *)
type t
val f : t -> b' list
end
(* bsig.mli *)
module type BT = sig
type a
type b' (* t = b' will be enforced externally *)
type t = { aaa: a list; bo: b' option }
val g : t -> b' list
end
(* b.ml *)
open Asig
module MakeB(A : AT) = struct
type a = A.t
type t = { aaa: a list; bo: A.b' option }
type b' = A.b'
let g b =
let ss = List.flatten (List.map A.f b.aaa) in
match b.bo with
| Some b' -> b' :: ss
| None -> ss
end
(* a.ml *)
open Asig
open Bsig
module type ASigFull = sig
type b
type b'
type t = Foo of b | Bar
val f : t -> b' list
end
module type BMAKER = functor (A : AT) -> (BT with type a = A.t
and type b' = A.b')
module MakeAB(MakeB : BMAKER) = struct
module rec B1 : (BT with type a = A1.t
and type b' = A1.b') = MakeB(A1)
and A1 : (ASigFull with type b = B1.t
and type b' = B1.t) = struct
type b = B1.t
type b' = b
type t = Foo of b | Bar
let f = function Foo b -> [ b ] | Bar -> []
end
module A = (A1 : ASigFull with type t = A1.t and type b = B1.t and type b' := B1.t)
module B = (B1 : BT with type t = B1.t and type a = A1.t and type b' := B1.t)
end
module AB = MakeAB(B.MakeB)
module A = AB.A
module B = AB.B
let a = A.Bar;;
let b = B.({ aaa = [a]; bo = None });;
let c = A.Foo b;;
let d = B.({ aaa = [a;c]; bo = Some b });;

Resources