I am starting to learn OCaml and was trying to do some practices:
# let left x y = x;;
val left : 'a -> 'b -> 'a = <fun>
# let first = List.fold_right left;;
val first : '_a list -> '_a -> '_a = <fun>
Why is first only weakly polymorphic instead of fully polymorphic?
This is the value restriction. first is not a value, it's a function application.
To get a fully polymorphic version, use eta expansion:
# let left x y = x;;
val left : 'a -> 'b -> 'a = <fun>
# let first a b = List.fold_right left a b;;
val first : 'a list -> 'a -> 'a = <fun>
As #ivg points out, this is a commonly asked OCaml question.
Update
Here's a function application that's unsafe to generalize:
# let f x = ref x;;
val f : 'a -> 'a ref = <fun>
# f [];;
- : '_a list ref = {contents = []}
If you pretend that the result has the type 'a list ref you can make the code go wrong (I tried it).
Here's a partial application that's unsafe to generalize:
# let g x = let z = ref x in fun () -> z;;
val g : 'a -> unit -> 'a ref = <fun>
# g [];;
- : unit -> '_a list ref = <fun>
If you pretend that the result has type unit -> 'a list ref you can make this code go wrong (I tried it).
Related
let app = fun f -> fun x -> f (x);;
(*val app : ('a -> 'b) -> 'a -> 'b = <fun>*)
let app = fun f -> fun x -> x (f+1);;
(*val app : int -> (int -> 'a) -> 'a = <fun>*)
let app = fun f -> fun x -> x (f);;
(*val app : 'a -> ('a -> 'b) -> 'b = <fun>*)
let app2 = fun f -> fun g -> fun x -> g ( f x );;
(*val app2 : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c = <fun>*)
let app2 = fun f -> fun g -> fun x -> f (g x );;
(*val app2 : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>*)
let app2 = fun f -> fun g -> fun x -> g (f x+1);;
(*val app2 : ('a -> int) -> (int -> 'b) -> 'a -> 'b = <fun>*)
let app2 = fun f -> fun g -> fun x -> f (g x+1 );;
(*val app2 : (int -> 'a) -> ('b -> int) -> 'b -> 'a = <fun>*)
let app3 = fun f -> fun g -> fun x -> g f x+1 ;;
(*val app3 : 'a -> ('a -> 'b -> int) -> 'b -> int = <fun>*)
How do I know what happens in the val line without tapping enter on the let app line.
To be more specific I dont understand the relation between let and val.
For example, for the first one:
let app = fun f -> fun x -> f (x);;
(*val app : ('a -> 'b) -> 'a -> 'b = <fun>*)
What I see is that the first x takes the name 'a
and after it goes to the f which takes the name 'b
and after it goes to the fun x which is 'a again
and after it goes to the fun y which is 'b again.
But it is clearly not the case with other functions.
How do I know how they are related?
Someone has put the types of these functions in comments below the actual code. Comments in OCaml are surrounded by (* and *).
These type signatures are identical to what you'd see in an OCaml toplevel. You enter an expression, followed by ;;, this code is evaluated, and you're shown the resulting value.
Consider:
# 4 + 5;;
- : int = 9
# let a = 4 + 5;;
val a : int = 9
#
The val only shows up if I've introduced a name for the value. In either case we're shown the type of the resulting value and the value itself.
When you see things like 'a and 'b you're seeing type variables that OCaml infers when it can't infer a specific type. This very recent question is worth reading.
let is used to create name-bindings(alternatively named definitions if you would like to call it), where a binding will have a name and will be bound to an expression, which when evaluated will produce a value.
fun is used to create/define anonymous function, Anonymous functions are function expression which means an expression of type function, which when evaluated given its arguments will produce a value, and this function expression can itself be passed around like any other regular value.. and this function expression is bound using a let.
For example
let app = fun f -> fun x -> x (f+1)
In this case, we are defining a name app which will be bound to the expression produced by fun on the right. The fun takes a parameter f whose type will be inferred by the compiler once it is done processing the body of that function expression. The same applies to the next function expression which takes a parameter named x.
By looking at the right-most expression, which is responsible for generating the reduced value, we see f getting applied to the operator + and so f will receive it's type from that expression. And then x (...) entails a function application, so the x will receive it's type from that expression.
And we can go on applying the same to every expression cited in the question.
Essentially, let bindings, lambda expressions, type inference, function application, function expression etc... are some of the topics one should get acquainted with to understand what's going on.
I don't understand that the function (my_path_mapper) doesn't subject to the value restriction.
# let rec my_map ~f l =
match l with
[] -> []
| h::t -> f h::my_map f t;;
val my_map : f:('a -> 'b) -> 'a list -> 'b list = <fun>
# let my_path_mapper =
my_map ["/usr/sbin"; "/usr/bin"; "/sbin"; "/bin"; "/usr/games"; "/usr/local/games"];;
val my_path_mapper : f:(string -> 'a) -> 'a list = <fun>
Please teach me Why ?
OCaml has a "relaxed value restriction." You can read about it here:
Jacques Garrigue, Relaxing the Value Restriction
Here is a previous discussion on StackOverflow:
When does the relaxed value restriction kick in in OCaml?
This question already has an answer here:
Why does OCaml sometimes require eta expansion?
(1 answer)
Closed 7 years ago.
Why does OCaml change the type of a value of first use when it contains a universal? For example, if we define a Church encoding for tuples, we have:
# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y-> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# first foo;;
- : float = 1.2
# foo;;
- : (float -> string -> float) -> float = <fun>
# second foo;;
Error: This expression has type (float -> string -> float) -> float
but an expression was expected of type
(float -> string -> string) -> 'a
Type float is not compatible with type string
# let foo = pair 1.2 "bob";;
val foo : (float -> string -> '_a) -> '_a = <fun>
# second foo;;
- : string = "bob"
# foo;;
- : (float -> string -> string) -> string = <fun>
# first foo;;
Error: This expression has type (float -> string -> string) -> string
but an expression was expected of type
(float -> string -> float) -> 'a
Type string is not compatible with type float
Basically, foo has type val foo : (float -> string -> '_a) -> '_a = <fun>, but this changes the first time we project out either the first or second element. Why does this happen?
This called a weak polymorphic type. Lots of questions were asked and answered about this. Feel free to use SO search facilities or read OCaml FAQ. But in short, this is due to value restriction, that usually comes into play when you have partial application or mutable values. In the former case your can strengthen your type with so called eta-expression (in a layman terms, by substituting partial application with normal function invocation). In the latter case, nothing can be made.
As #ivg says, this is the value restriction. Here is how things work if you use eta expansion:
# let pair x y z = z x y;;
val pair : 'a -> 'b -> ('a -> 'b -> 'c) -> 'c = <fun>
# let first p = p (fun x y -> x);;
val first : (('a -> 'b -> 'a) -> 'c) -> 'c = <fun>
# let second p = p (fun x y -> y);;
val second : (('a -> 'b -> 'b) -> 'c) -> 'c = <fun>
# let foo x = pair 1.2 "bob" x;;
val foo : (float -> string -> 'a) -> 'a = <fun>
# first foo;;
- : float = 1.2
# second foo;;
- : string = "bob"
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.
First the code:
module type ENV_CORE =
sig
type variable
type 'a environment
exception Unbound_variable
val empty : unit -> variable
val bind : 'a -> 'a environment -> 'a environment
val unbind : variable -> 'a -> 'a environment -> 'a environment
val is_bound : variable -> 'a environment -> bool
val lookup : variable -> 'a environment -> bool
val fold : (variable -> 'a -> 'b -> 'b) -> 'a environment -> 'b -> 'b
end;;
module EnvCoreList : ENV_CORE =
struct
type variable = string list
type 'a environment = variable * variable -> 'a
exception Unbound_variable
let empty () = []
let bind elt l = elt::l
let rec unbind elt l =
match l with
|[] -> raise Unbound_variable
|a::r -> if (elt = a)
then r
else a::(unbind elt r)
let rec is_bound elt l =
match l with
|[] -> raise Unbound_variable
|a::r -> if (elt = a)
then true
else is_bound elt r
let rec lookup elt l =
match l with
|[] -> false
|a::r -> if (elt = a)
then true
else lookup elt r
let rec fold f rho gamma =
match rho with
|[] -> gamma
|a::r -> f a (fold f r gamma)
end;;
When I compile it I get the following error:
Error: Signature mismatch:
Modules do not match:
sig
type variable = string list
type 'a environment = variable * variable -> 'a
exception Unbound_variable
val empty : unit -> 'a list
val bind : 'a -> 'a list -> 'a list
val unbind : 'a -> 'a list -> 'a list
val is_bound : 'a -> 'a list -> bool
val lookup : 'a -> 'a list -> bool
val fold : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
end
is not included in
ENV_CORE
Values do not match:
val bind : 'a -> 'a list -> 'a list
is not included in
val bind : 'a -> 'a environment -> 'a environment
What I don't understand is how the more specific type isn't included in the more general type?
I couldnt find any similar questions and havent been able to resolve this issue.
Thanx
There's no obvious relation between the types 'a list and 'a environment. I don't see why you would consider either to be more general than the other.
It seems to me you should either change your definition of environment in your implementation, or you should rewrite bind so that it works on the type you specify for environment.