I tried to find this somewhere in internet, but I failed to do this. I want to learn OCaml and that's difficult to understand for me, how to do this.
My question is - how can I easy write a function, when I have a signature. For example - I have a signature like this:
((int -> int) -> int -> int -> int) -> (int -> int) -> int -> int -> int
and I want to write a function, that have signature like this above. Would someone help me or try to explain this? I would be very grateful :)
A function with type 'a -> 'b, takes values of some type 'a and returns values of some type 'b. To use specific types, a function of type int -> int takes an int and returns an int. This is the type of integer negation, for example.
One way to look at a function with type 'a -> 'b -> 'c is that it takes two values, of type 'a and 'b, and returns a value of type 'c. A specific example would be the type int -> int -> int, which is the type of integer addition (say):
# (+);;
- : int -> int -> int = <fun>
This pattern continues for more arguments.
The type you give has this type at the high level: 'a -> 'b -> 'c -> 'd -> 'e. So, it's a function with four arguments.
The first argument has type (int -> int) -> int -> int -> int, which is itself quite complicated. The second argument has type int -> int, described above. The third and fourth arguments have type int. The function returns an int.
Using this same analysis on the first argument, you can see that it's a function with three arguments. The first is a function of type int -> int, and the second and third are of type int. This function returns an int.
Here's a function of type (int -> int) -> int -> int -> int:
let myfun f a b =
(f a) + a + b
You can see the type in the OCaml toplevel:
# let myfun f a b =
(f a) + a + b;;
val myfun : (int -> int) -> int -> int -> int = <fun>
#
You should be able to work out the rest. I don't want to take all the enjoyment out of the problem by giving a full answer.
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.
(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)
fun bar f b nil = b
| bar f b (h::t) = f (h, bar f b t)
This function was given to us with the instructions of explaining what it does. The only further information given are that the parameters are a binary function, a value, and a list. From looking at it, I already know that if the list is nil, it returns the b value, otherwise it applies the binary function to the list head and recurses. I just don't understand how to interpret this line:
(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)
There are numerous tutorials explaining SML's typing, but I can't find anything in-depth enough to apply to this. Could anyone translate it to English so I know how it works for future reference?
To understand this type sgnature, you need to first understand currying.
A definition like
fun sum a b = a + b
has type int -> int -> int.
It is a function of one variable (an integer) where the return value is itself a function, one which sends ints to ints.
For example, val f = sum 1 assigns to f the function which adds one to its input (in other words, the successor function) so that, e.g., f 5 evaluates to 6.
In practice, such functions are often used like sum 3 4 but what is happening there isn't the passing of 2 values to sum. Rather, the one value 3 is passed, which returns a function, and this returned value is then applied to 4. Thus, sum 3 4 should be parsed as (sum 3) 4 rather than sum (3,4) -- which would be a type error.
Note that this is fundamentally different from something like
fun add (a,b) = a + b
which is a function of two variables, it has type int * int -> int, which is different than sum's type of int -> int -> int. The latter is not syntactic sugar for the former, but instead has a fundamentally different semantics.
When reading something such as int -> int -> int, you should read it as right-associative. In other words, it is the same as int -> (int -> int).
Another thing that is happening with ('a * 'b -> 'b) -> 'b -> 'a list -> 'b is the use of type variables 'a, 'b. This means that the type you are trying to parse is of a higher-order polymorphic function. It 'a and 'b can represent any type.
Putting it all together, a function, f, of type ('a * 'b -> 'b) -> 'b -> 'a list -> 'b is a function which takes as input any function whose type is of the form 'a * 'b -> 'b (a function of two variables whose return type is the type of the second variable). The return value of f is a function of the form 'b -> 'a list -> 'b. This latter is a function which takes an element of type 'b and returns a function which sends 'a lists to objects of type 'b
You could summarize it by saying that f is a curried function which takes a function of type ('a * 'b -> 'b), a value of type 'b, a list of values of type 'a, and returns a value of type 'b. That is accurate enough, but don't slip into thinking of it as equivalent to a function of type
('a * 'b -> 'b) * 'b * 'a list -> 'b
By the way, two of the most useful functions in SML, foldl and foldr have type ('a * 'b -> 'b) -> 'b -> 'a list -> 'b, so this isn't merely an academic exercise. Being able to unpack such type descriptions is a key to being able to use such functions correctly.
I was able to find the solution based on what is apparently called type inferencing. I had never learned this before but
(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)
is display of argument and return types for the function.
(’a * ’b -> ’b) refers to the first argument function. It requires 2 arguments ('b and 'a) in itself and returns 1 value 'b.
'b refers to the second argument, a value.
'a list refers to a list of values, the third argument in the function.
Finally, the last 'b is the return value.
Function specification:
Write a function any_zeroes : int list -> bool that returns true if and only if the input list contains at least one 0
Code:
let any_zeroes l: int list =
List.exists 0 l
Error:
This expression has type int but an expression was expected of type
'a -> bool
I don't know why Ocaml is having an issue with the 0 when I marked l to be an int list. If anyone could help me fix the issue this would be greatly appreciated!
Thanks!
So, first of all, you didn't mark l as int list, the syntax:
let any_zeroes l: int list
Means that the any_zeroes is a function, that returns an int list. A correct way to annotate it, is the following:
let any_zeroes (l : int list) : bool
Second, the fact, that you mark something doesn't change the semantics of a program. It is a type constraint, that tells the type inference system, that you want this type to be unified to whatever you specified. If a type checker can't do this, it will bail out with an error. And type checker don't need your constraints, they are mostly added for readability. (I think they are also required by the course that you're taking).
Finally, the error points you not to the l (that, as you think, was annotated), but to the 0. And the message tells you, that List.exists function is accepting a function of type 'a -> bool as the first argument, but you're trying to feed it with 0 that has type int. So, the type system is trying to unify int and 'a list, and there is no such 'a that int = 'a list, so it doesn't type check. So you either need to pass a function, or to use List.mem as was suggested by Anton.
The type annotation let any_zeroes l: int list = ... means the type of any_zeroes l is int list; this is not what you mean here.
The correct type annotation related to your specification is:
let any_zeroes
: int list -> bool
= fun l -> List.exists 0 l
In the top level, it feedbacks:
= fun l -> List.exists 0 l;;
^
This expression has type int but an expression was expected of type
'a -> bool
Indeed, this expression fails to typecheck because of the type of List.exists:
# List.exists;;
- : ('a -> bool) -> 'a list -> bool = <fun>
The first argument is a predicate, which 0 is not.
A correct implementation is:
let any_zeroes
: int list -> bool
= let is_zero x = x = 0 in
fun l -> List.exists is_zero l
I want to define a function that accepts an optional argument which is a function ('a -> 'b). The default value should be the identity, which is actually ('a -> 'a), but i see no reason why it should not be compatible with the more general ('a -> 'b). When i try:
let optional_apply ?f i =
match f with
| None -> i + 4
| Some fn -> fn (i + 4)
I always get the narrow type ?f:(int -> int) -> int -> int. But I want to keep f as int -> 'b. What can i do? Or is this just unsound, since optional_apply would not have a definite type? If so, how would I get a similar functionality?
It is impossible, the f argument must not be optional. A simple explanation, is that optional parameters are just a syntactic sugar.
So without sugar your function can be rewritten in a following form:
let optional_apply f n = match f with
| Some f -> f (n + 4)
| None -> (n + 4)
And here typechecker allows us only one type for f: int -> int. If it allowed us an int -> 'a type, then the None path of expression would be unsound. In other words, depending on whether f is None or Some the optional_apply will evaluate to different types. And this is considered unsound.
The best way to prove the unsoundness is to give a simple example where typechecker will allow unsound program:
let f = ref None
let g n = optional_apply ?f:!f n
with this definitions, if type checker allowed f parameter to remain polymorphic, then we can at any time "break" g function by changing f reference to anything else.
This is not compatible with the general type ('a -> 'b). Here's why:
The first pattern, None -> i + 4 is of type int, thus restricting the function's return type to int.
The second pattern, Some fn -> fn (i + 4) must then also be of type int. Because (i + 4) is of type int, too, fn must take and return an int, thus int -> int.
The best alternative I can think of is Haskell's maybe function, of type ('a -> 'b) -> 'b -> 'a option -> 'b:
let maybe fn backup opt = match opt with
| Some v -> fn v
| None -> backup
;;
... which you can probably adapt to your use case.
I want to write a function of type
int -> 'a -> (int, int) slowa list
I was wondering would I necessarily need to defing first a type slowa
If so, this is how I defined my "slowa"
type slowa =
(_,_)
|('a, 'b) of int * int
;;
Where slowa is of type (int, int)
But I'm not sure how if I am thinking right. I'd appreciate some help. I'm new to this :)
EDIT:
So now I went ahead to try this:
type ('b, 'a) slowa = int * 'b
let c = 3, 5;;
let d = 1, 3;;
let rec add k v d =
match d with
| [] -> [(k, v)]
| (k', v')::t ->
if k = k'
then (k, v) :: t
else (k', v') :: add k v t
;;
but I want it the type of the function add to be like this type: int -> 'a -> (int, int) slowa list
It would be easier if I wanted to return just list but now the return type is int -> 'a -> (int, int) slowa list which gets confusing... :/ I stand to be correct on the number/type of parameters.
If you just want a type that's a synonym for int * int (pairs of ints), you can define it like this:
type slowa = int * int
In this case, the name is just a synonym. You could always replace uses of the name by the definition. So you don't actually need to make the definition (it's good for documentation).
If you want to define a new type, you need to define a constructor for it:
type myslowa = Slow of int * int
This defines a new type. Values of the type look like Slow (3, 4). These values have a type different from all others; i.e., they are not interchangeable with pairs of ints.
If you want to define a parameterized type, you need to include the parameter(s) in your definition:
type ('a, 'b) pslowa = 'a * 'b
Since there's no new constructor, this is also just a synonym. But it's a synonym for an infinite set of types. In particular, it's a synonym for pairs of any two types.
If you want to define a new, parameterized type, you need to have both parameters and a constructor:
type ('a, 'b) mypslowa = Slow of 'a * 'b
This combines the properties; i.e., it is a new type that represents pairs of any two types.
I hope this helps; one of these might be close to what you're looking for.
Update
With your new definition of slowa, the type (int, int) slowa is identical to the type int * int. When the toplevel shows you the type of something, it has to choose among all the ways of representing the type. I think what you're saying is that the toplevel chooses to use int * int rather than (int, int) slowa. It's best not to get too hung up on this (IMHO). The one thing you might try is to annotate your types:
type ('b, 'a) slowa = int * 'b
let c = 3, 5;;
let d = 1, 3;;
let rec add k v (d: ('a, 'b) slowa list) : ('a, 'b) slowa list =
match d with
| [] -> [(k, v)]
| (k', v')::t ->
if k = k'
then (k, v) :: t
else (k', v') :: add k v t
;;
(Your definition of slowa looks a little strange, since you're not using the 'a parameter for anything.)