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.
Related
If I have a function f defined as
f: 'a -> 'b -> c' -> d'
Does that mean it takes one argument? Or 3? And then it outputs one argument? How would I use or call such a function?
As Glennsl notes in the comments, it means both.
Very briefly, and by no means comprehensively, from an academic perspective, no function in OCaml takes more than one argument or returns more or less than one value. For instance, a function that takes a single argument and adds 1 to it.
fun x -> x + 1
We can give that function a name in one of two ways:
let inc = fun x -> x + 1
Or:
let inc x = x + 1
Either way, inc has the type int -> int which indicates that it takes an int and returns an int value.
Now, if we want to add two ints, well, functions only take one argument... But functions are first class things, which means a function can create and return another function.
let add =
fun x ->
fun y -> x + y
Now add is a function that takes an argument x and returns a function that takes an argument y and returns the sum of x and y.
We could use a similar method to define a function that adds three ints.
let add3 =
fun a ->
fun b ->
fun c -> a + b + c
The type of add would be int -> int -> int and add3 would have type int -> int -> int -> int.
Of course, OCaml is not purely an academic language, so there is convenience syntax for this.
let add3 a b c = a + b + c
Inferred types
In your question, you ask about a type 'a -> 'b -> 'c -> 'd``. The examples provided work with the concrete type int. OCaml uses type inferencing. The compiler/interpreter looks at the entire program to figure out at compile time what the types should be, without the programmer having to explicitly state them. In the examples I provided, the +operator only works on values of typeint, so the compiler _knows_ incwill have typeint -> int`.
However, if we defined an identity function:
let id x = x
There is nothing her to say what type x should have. In fact, it can be anything. But what can be determined, if that the function will have the same type for argument and return value. Since we can't put a concrete type on that, OCaml uses a placeholder type 'a.
If we created a function to build a tuple from two values:
let make_tuple x y = (x, y)
We get type 'a -> 'b -> 'a * 'b.
In conclusion
So when you ask about:
f: 'a -> 'b -> 'c -> 'd
This is a function f that takes three arguments of types 'a, 'b, and 'c and returns a value of type 'd.
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.)
I've been learning OCaml recently and as of now it would seem an arrow is used by the compiler to signify what the next type would be. For instance, int -> int -> <fun> an integer which returns an integer, which returns a function.
However, I was wondering if I can use it natively in OCaml code. In addition, if anyone would happen to know the appropriate name for it. Thank you.
The operator is usually called type arrow where T1 -> T2 represents functions from type T1 to type T2. For instance, the type of + is int -> (int -> int) because it takes two integers and returns another one.
The way -> is defined, a function always takes one argument and returns only one element. A function with multiple parameters can be translated into a sequence of unary functions. We can interpret 1 + 2 as creating a +1 increment function (you can create it by evaluating (+) 1 in the OCaml command line) to the number 2. This technique is called Currying or Partial Evaluation.
Let's have a look at OCaml's output when evaluating a term :
# 1 + 2;;
- : int = 3
# (+) 1 ;;
- : int -> int = <fun>
The term1+2 is of type integer and has a value of 3 and the term (+) 1 is a function from integers to integers. But since the latter is a function, OCaml cannot print a single value. As a placeholder, it just prints <fun>, but the type is left of the =.
You can define your own functions with the fun keyword:
# (fun x -> x ^ "abc");;
- : bytes -> bytes = <fun>
This is the function which appends "abc" to a given string x. Let's take the syntax apart: fun x -> term means that we define a function with argument x and this x can now appear within term. Sometimes we would like to give function names, then we use the let construction:
# let append_abc = (fun x -> x ^ "abc") ;;
val append_abc : bytes -> bytes = <fun>
Because the let f = fun x -> ... is a bit cumbersome, you can also write:
let append_abc x = x ^ "abc" ;;
val append_abc : bytes -> bytes = <fun>
In any case, you can use your new function as follows:
# append_abc "now comes:" ;;
- : bytes = "now comes:abc"
The variable x is replaced by "now comes:" and we obtain the expression:
"now comes:" ^ "abc"
which evaluates to "now comes:abc".
#Charlie Parker asked about the arrow in type declarations. The statement
type 'a pp = Format.formatter -> 'a -> unit
introduces a synonym pp for the type Format.formatter -> 'a -> unit. The rule for the arrow there is the same as above: a function of type 'a pp takes a formatter, a value of arbitrary type 'a and returns () (the only value of unit type)
For example, the following function is of type Format.formatter -> int -> unit (the %d enforces the type variable 'a to become int):
utop # let pp_int fmt x = Format.fprintf fmt "abc %d" x;;
val pp_int : formatter -> int -> unit = <fun>
Unfortunately the toplevel does not infer int pp as a type so we don't immediately notice(*). We can still introduce a new variable with a type annotation that we can see what's going on:
utop # let x : int pp = pp_int ;;
val x : int pp = <fun>
utop # let y : string pp = pp_int ;;
Error: This expression has type formatter -> int -> unit
but an expression was expected of type
string pp = formatter -> string -> unit
Type int is not compatible with type string
The first declaration is fine because the type annotation agrees with the type inferred by OCaml. The second one is in conflict with the inferred type ('a' can not be both int and string at the same time).
Just a remark: type can also be used with records and algebraic data types to create new types (instead of synonyms). But the type arrow keeps its meaning as a function.
(*) Imagine having multiple synonymes, which one should the toplevel show? Therefore synonyms are usually expanded.
The given answer doesn't work for ADTs, GADTs, for that see: In OCaml, a variant declaring its tags with a colon
e.g.
type 'l generic_argument =
| GenArg : ('a, 'l) abstract_argument_type * 'a -> 'l generic_argument
Let's say I have a list of options:
let opts = [Some 1; None; Some 4]
I'd like to convert these into an option of list, such that:
If the list contains None, the result is None
Otherwise, the various ints are collected.
It's relatively straightforward to write this for this specific case (using Core and the Monad module):
let sequence foo =
let open Option in
let open Monad_infix in
List.fold ~init:(return []) ~f:(fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) foo;;
However, as the question title suggests, I'd really like to abstract over the type constructor rather than specialising to Option. Core seems to use a functor to give the effect of a higher kinded type, but I'm not clear how I can write the function to be abstracted over the module. In Scala, I'd use an implicit context bound to require the availability of some Monad[M[_]]. I'm expecting that there's no way of implicitly passing in the module, but how would I do it explicitly? In other words, can I write something approximating this:
let sequence (module M : Monad.S) foo =
let open M in
let open M.Monad_infix in
List.fold ~init:(return []) ~f:(fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) foo;;
Is this something that can be done with first class modules?
Edit: Okay, so it didn't actually occur to me to try using that specific code, and it appears it's closer to working than I'd anticipated! Seems the syntax is in fact valid, but I get this result:
Error: This expression has type 'a M.t but an expression was expected of type 'a M.t
The type constructor M.t would escape its scope
The first part of the error seems confusing, since they match, so I'm guessing the problem is with the second - Is the problem here that the return type doesn't seem to be determined? I suppose it's dependent on the module which is passed in - is this a problem? Is there a way to fix this implementation?
First, here is a self-contained version of your code (using the legacy
List.fold_left of the standard library) for people that don't have
Core under hand and still want to try to compile your example.
module type MonadSig = sig
type 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val return : 'a -> 'a t
end
let sequence (module M : MonadSig) foo =
let open M in
let (>>=) = bind in
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
The error message that you get means (the confusing first line can
be ignored) that the M.t definition is local to the M module, and
must not escape its scope, which it would do with what you're trying
to write.
This is because you are using first-class modules, that allow to
abstract on modules, but not to have dependent-looking types such as
the return type depends on the argument's module value, or at least
path (here M).
Consider this example:
module type Type = sig
type t
end
let identity (module T : Type) (x : T.t) = x
This is wrong. The error messages points on (x : T.t) and says:
Error: This pattern matches values of type T.t
but a pattern was expected which matches values of type T.t
The type constructor T.t would escape its scope
What you can do is abstract on the desired type before you abstract on the first-class module T, so that there is no escape anymore.
let identity (type a) (module T : Type with type t = a) (x : a) = x
This relies on the ability to explicitly abstract over the type variable a. Unfortunately, this feature has not been extended to abstraction over higher-kinded variables. You currently cannot write:
let sequence (type 'a m) (module M : MonadSig with 'a t = 'a m) (foo : 'a m list) =
...
The solution is to use a functor: instead of working at value level, you work at the module level, which has a richer kind language.
module MonadOps (M : MonadSig) = struct
open M
let (>>=) = bind
let sequence foo =
List.fold_left (fun acc x ->
acc >>= fun acc' ->
x >>= fun x' ->
return (x' :: acc')
) (return []) foo;;
end
Instead of having each monadic operation (sequence, map, etc.) abstract over the monad, you do a module-wide abstraction.