I was trying to unwrap the result of List.max_elt of a non-empty list, which should always exist, so I thought Option.value_exn would be the correct tool. But it fails with a strange error:
# List.range 0 10 |> List.max_elt ~cmp:compare;;
- : int option = Some 9
# Option.value_exn (Some 9);;
- : int = 9
# List.range 0 10 |> List.max_elt ~cmp:compare |> Option.value_exn;;
Error: This expression has type
?here:Lexing.position ->
?error:Base.Error.t -> ?message:string -> 'a Base.option -> 'a
but an expression was expected of type int option -> 'b
Can anybody explain this error to me?
I'm using OCaml 4.05.0 and the latest Core library.
The problem here is that something (I'm guessing Option.value_exn) takes optional arguments. When you write it as Option.value_exn x OCaml knows that the optional arguments aren't being used, but when you write it as x |> Option.value_exn it doesn't.
Related
I meet an error about subtyping.
For this code, List.map (fun ((String goal_feat):> Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list).
I meet the following error in vscode:
This expression cannot be coerced to type
Yojson.Basic.t =
[ Assoc of (string * Yojson.Basic.t) list
| Bool of bool
| Float of float
| Int of int
| List of Yojson.Basic.t list
| Null
| String of string ];
it has type [< String of 'a ] -> 'b but is here used with type
[< Yojson.Basic.t ].
While compiling, I meet the following error.
Error: Syntax error: ')' expected.
If I change the code to List.map (fun ((String goal_feat): Basic.t) -> goal_feat) (goal_feats_json:> Basic.t list), which useq explicit type cast instead of subtyping, then the error disappeared. I can not understand what is the problem with my code when i use subtyping. Much appreciation to anyone who could give me some help.
First of all, most likely the answer that you're looking for is
let to_strings xs =
List.map (function `String x -> x | _ -> assert false) (xs :> t list)
The compiler is telling you that your function is handling only one case and you're passing it a list that may contain many other things, so there is a possibility for runtime error. So it is better to indicate to the compiler that you know that only the variants tagged with String are expected. This is what we did in the example above. Now our function has type [> Yojson.Basic.t].
Now back to your direct question. The syntax for coercion is (expr : typeexpr), however in the fun ((String goal_feat):> Basic.t) -> goal_feat snippet, String goal_feat is a pattern, and you cannot coerce a pattern, so we shall use parenthesized pattern here it to give it the right, more general, type1, e.g.,
let exp xs =
List.map (fun (`String x : t) -> x ) (xs :> t list)
This will tell the compiler that the parameter of your function shall belong to a wider type and immediately turn the error into warning 8,
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
(`Bool _|`Null|`Assoc _|`List _|`Float _|`Int _)
which says what I was saying in the first part of the post. It is usually a bad idea to leave warning 8 unattended, so I would suggest you to use the first solution, or, otherwise, find a way to prove to the compiler that your list doesn't have any other variants, e.g., you can use List.filter_map for that:
let collect_strings : t list -> [`String of string] list = fun xs ->
List.filter_map (function
| `String s -> Some (`String s)
| _ -> None) xs
And a more natural solution would be to return untagged strings (unless you really need the to be tagged, e.g., when you need to pass this list to a function that is polymorphic over [> t] (Besides, I am using t for Yojson.Basic.t to make the post shorter, but you should use the right name in your code). So here is the solution that will extract strings and make everyone happy (it will throw away values with other tags),
let collect_strings : t list -> string list = fun xs ->
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
Note, that there is no need for type annotations here, and we can easily remove them to get the most general polymoprhic type:
let collect_strings xs =
List.filter_map (function
| `String s -> Some s
| _ -> None) xs
It will get the type
[> `String a] list -> 'a list
which means, a list of polymorphic variants with any tags, returning a list of objects that were tagged with the String tag.
1)It is not a limitation that coercion doesn't work on patterns, moreover it wouldn't make any sense to coerce a pattern. The coercion takes an expression with an existing type and upcasts (weakens) it to a supertype. A function parameter is not an expression, so there is nothing here to coerce. You can just annotate it with the type, e.g., fun (x : #t) -> x will say that our function expects values of type [< t] which is less general than the unannotated type 'a. To summarize, coercion is needed when you have a function that accepts an value that have a object or polymorphic variant type, and in you would like at some expressions to use it with a weakened (upcasted type) for example
type a = [`A]
type b = [`B]
type t = [a | b]
let f : t -> unit = fun _ -> ()
let example : a -> unit = fun x -> f (x :> t)
Here we have type t with two subtypes a and b. Our function f is accepting the base type t, but example is specific to a. In order to be able to use f on an object of type a we need an explicit type coercion to weaken (we lose the type information here) its type to t. Notice that, we do not change the type of x per se, so the following example still type checks:
let rec example : a -> unit = fun x -> f (x :> t); example x
I.e., we weakened the type of the argument to f but the variable x is still having the stronger type a, so we can still use it as a value of type a.
Taking an exemple derived from RWOCaml :
utop # let divide ~first ~second = first / second;;
val divide : first:int -> second:int -> int = <fun>
utop # let apply_to_tuple_3 f (first,second) = f second first;;
val apply_to_tuple_3 : ('a -> 'b -> 'c) -> 'b * 'a -> 'c = <fun>
utop # apply_to_tuple_3 divide;;
Error: This expression has type first:int -> second:int -> int
but an expression was expected of type 'a -> 'b -> 'c
Does it make sense to not match the types here ?
apply_to_tuple_3 only makes use of the positional arguments, which certainly divide possesses.
Upon removing the names, the application is accepted
utop # let divide_an x y = divide x y;;
val divide_an : int -> int -> int = <fun>
utop # apply_to_tuple_3 divide_an;;
- : int * int -> int = <fun>
Is there any reason to reject the first call ?
Functions with labeled parameters have a type that depends on the labels and on the order that they appear. When calling such functions, there is flexibility in the order of arguments that you supply. And in fact you can omit the labels if you supply all of the arguments.
However, when passing such functions as values themselves, there is no such flexibility. You have only the one labeled type to work with.
This is covered on page 42 of Real World OCaml: Higher-order functions and labels.
(If you're asking why this is the case, I can only assume that type checking becomes difficult or impossible if you allow such flexibility.)
List.map is of type
- : ('a -> 'b) -> 'a list -> 'b list = <fun>
It's easy for me to understand the following code:
List.map (fun x -> x+1) [1;2;3;4];;
which adds 1 to each element of the list so it returns the following list :
- : int list = [2;3;4;5]
Now this is in an exercise where I'm asked to indicate the type of this :
List.map (fun p -> p 7) [ (fun n m -> n + m) ];;
I don't understand at all what it means to be honest.
What does p 7 mean ?
Why is there a function in the list ?
The type is
- : (int -> int) list = [<fun>]
But I can't understand why.
What does it mean when fun is between brackets ?
Thank you.
What does p 7 mean?
It means the application of function p to argument 7 .... You might spend some time reading the wikipage on λ-calculus (at least to learn about functional abstraction)
Read also about currying.
Why is there a function in the list ?
In Ocaml, functions are values, so you can have list of functions. If it was not a list of functions, you'll get a typing error. If you think more, you can understand what kind of functions are allowed.
What does it mean when fun is between brackets ?
The toplevel is not able to print functional values (implemented as closures). It shows them as <fun>. For a simpler example, pass fun x -> x+1;; (then try also fun y -> y;;) to your REPL.
(the rest of the exercise is left to the reader)
I have anonymous function:
fun x -> x;;
- : 'a -> 'a = <fun>
As you may see, this function accepts argument of any type. I want to specify concrete type, say int.
I know that I can annotate functions with type specs, but do not know syntax for it.
It would be helpful to get some reference to this syntax and extend this example with such annotation.
Thanks.
# fun (x: int) -> x;;
- : int -> int = <fun>
#
The reason this works is that
Function parameters are specified as patterns.
One alternative for a patttern is of the form:
( pattern : typexpr )
Syntax for patterns is given in Section 6.6 of the OCaml manual.
The most general form is:
(fun x -> x : int -> int)
Since fun x -> x is a value by itself, it can be annotated with a type, as any other expression. Indeed, in this type annotation you can omit one of the int's, since the other can be inferred by a compiler:
(fun x -> x : int -> 'a)
or
(fun x -> x : 'a -> int)
all will result in:
- : int -> int = <fun>
This also demonstrates that 'a in type annotations has different meaning from 'a in signatures. In type annotation it stands for "I don't care, you decide". Thats why the proper name for type annotations is type constraining, thus you're not annotating your expression with type, but you're giving extra constraint for type inference system. In this example, you're saying to it: I have this expression, and please infer its type, giving it is a function that returns int.
Also, you can use _ instead of type variables, the same way as you can do this for a normal variables:
(fun x -> x : _ -> int)
The result will be the same.
In OCaml, is there a way to refer to the cons operator by itself?
For example, I can use (+) and ( * ) as int -> int -> int functions, but I cannot use (::) as a 'a -> 'a list -> 'a list function, as the following example show:
# (+) 3 5;;
- : int = 8
# ( * ) 4 6;;
- : int = 24
# (::) 1 [2;3;4];;
Error: Syntax error: operator expected.
Is there a way to produce a result like (::) other than with fun x y -> x::y? And does anyone know why (::) wasn't implemented in OCaml?
Adding to the answer of #seanmcl,
Actually OCaml supports a prefix form of (::):
# (::)(1, []);;
- : int list = [1]
This is in the uncurried form, corresponding with the fact that all the OCaml variant constructors are not curried and cannot be partially applied. This is handled by a special parsing rule just for (::), which is why you got a rather strange error message Error: Syntax error: operator expected..
Update:
Upcoming OCaml 4.02 removes this parsing rule, therefore this is no longer available.
No. Cons (::) is a constructor, constructors can not be infix operators. The allowed infix symbols are here:
http://caml.inria.fr/pub/docs/manual-caml-light/node4.9.html
Some workarounds are (as you mention) the verbose
(fun x l -> x :: l)
and defining your own nontraditional infix cons
let (+:) x l = x :: l
As of Ocaml 4.03, you can now use cons (in the List module). That is, cons x xs is the same as x :: xs.
It's also possible to just define your own cons function:
let cons = fun a list -> a :: list