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?
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 want to implement the List.assoc function using List.find, this is what I have tried:
let rec assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> try (List.find (fun x -> a = x) lista)
b
with Not_found -> assoc l x;;
but it gives me this error:
This expression has type ('a * 'b) list but an expression was expected of type 'a list
The type variable 'a occurs inside 'a * 'b
I don't know if this is something expected to happen or if I'm doing something wrong. I also tried this as an alternative:
let assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> match List.split lista with
| (l1,l2) -> let ind = find l1 (List.find (fun s -> compare a x = 0))
in List.nth l2 ind;;
where find is a function that returns the index of the element requested:
let rec find lst x =
match lst with
| [] -> raise Not_found
| h :: t -> if x = h then 0 else 1 + find t x;;
with this code the problem is that the function should have type ('a * 'b) list -> 'a -> 'b, but instead it's (('a list -> 'a) * 'b) list -> ('a list -> 'a) -> 'b, so when I try
assoc [(1,a);(2,b);(3,c)] 2;;
I get:
This expression has type int but an expression was expected of type
'a list -> 'a (refering to the first element of the pair inside the list)
I don't understand why I don't get the expected function type.
First off, a quick suggestion on making your assoc function more idiomatic OCaml: have it take the list as the last argument.
Secondly, why are you attempting to implement this in terms of find? It's much easier without.
let rec assoc x lista =
match lista with
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
Something like this is simpler and substantially more efficient with the way lists work in OCaml.
Having the list as the last argument, even means we can write this more tersely.
let rec assoc x =
function
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
As to your question, OCaml infers the types of functions from how they're used.
find l1 (List.find (fun s -> compare a x = 0))
We know l1 is an int list. So we must be trying to find it in an int list list. So:
List.find (fun s -> compare a x = 0)
Must return an int list list. It's a mess. Try rethinking your function and you'll end up with something much easier to reason about.
In the List module of OCaml, how is : val assoc : 'a -> ('a * 'b) list -> 'b implemented and (therefore) what is the complexity of this operation ? Is there a hashtbl hidden behind the scenes ?
The code is available online here: https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.ml#L180-L182
let rec assoc x = function
[] -> raise Not_found
| (a,b)::l -> if compare a x = 0 then b else assoc x l
As you can see it's implemented as a linear search over the list.
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).
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.