I started learning functional programming (OCaml), but I don't understand one important topic about functional programming: types.
Can anyone explain me this solution please?
Have a test this week and can't get reach the resolution..
let f a b c = a (a b c) 0;;
f: ('a -> int -> 'a) -> 'a -> int -> 'a
let f a b c = a (a b c) 0;;
Your confusion involves types and type inference, i.e., when you define a function or binding, you don't need to give explicit types for its parameters, nor the function/binding itself, OCaml will figure it out if your definition of function/binding is correct.
So, let's do some manual inferences ourselves. If a human can do, then the compiler can also do.
1.
let x = 1
1 is integer, so x must be an integer. So you don't need to do int x = 1 as in other languages, right?
2.
let f x = 1
If there are multiple variable names between let and =, then it must be a function definition, right? Otherwise, it won't make sense. In Java like language, it also makes no sense to say int x y = 1, right?
So f is a function and x is must be a parameter. Since the righthand side of = is an integer, then we know f will return an integer. For x, we don't know, so x will be thought as a polymorphic type 'a.
So f: 'a -> int = <fun>.
3.
let f a b c = a (a b c) 0;;
f is a function, with parameters a, b, c.
a must be a function, because on the righthand side of =, it is a function application.
a takes two arguments: (a b c) and 0. 0 is an integer, so the 2nd parameter of a must be an integer type.
Look inside (a b c), c is the 2nd arguement, so c must be integer.
We can't infer on b. So b is 'a.
Since (a b c) can be the 1st argument of a, and (a b c) itself is an application on function a, the return type of a will have the same type of b which is 'a.
Combine information above together, you get f: ('a -> int -> 'a) -> 'a -> int -> 'a.
If you want to learn it formally, https://realworldocaml.org/ is your friend.
Related
I face a situation where a record is given a weak polymorphic type and I am not sure why.
Here is a minimized example
module type S = sig
type 'a t
val default : 'a t
end
module F (M : S) = struct
type 'a record = { x : 'a M.t; n : int }
let f = { x = M.default; n = (fun x -> x) 3 }
end
Here f is given the type '_weak1 record.
There are (at least) two ways to solve that problem.
The first one consists in using an auxiliary definition for the function application.
let n = (fun x -> x) 3
let f = { x = M.default; n }
The second one consists in declaring the type parameter of t as covariant.
module type S = sig
type +'a t
val default : 'a t
end
What I find strange is that the function application is used to initialize the field of type int that has no link at all with the type variable 'a of type t. And I also fail to see why declaring 'a as covariant suddenly allows to use arbitrary expressions in this unrelated field without losing polymorphism.
For your first point, the relaxed value restriction is triggered as soon as any computation happens in any sub-expression. Thus
neither
{ x = M.default; n = (fun x -> x) 3 }
nor
let n = Fun.id 3 in { x = M.default; n }
are considered a value and the value expression applies to both of them.
For your second point, this the relaxed value restriction at work: if a type variable only appears in strictly covariant positions, it can always be generalized. For instance, the type of
let none = Fun.id None
is 'a. 'a option and not '_weak1 option because the option type constructor is covariant in its first parameter.
The brief explanation for this relaxation of the value restriction is that a covariant type parameter corresponds to a positive immutable piece of data, for instance
type !+'a option = None | Some of 'a
or
type +'a t = A
Thus if we have a type variable that only appear in strictly covariant position, we know that it is not bound to any mutable data, and it can thus be safely generalized.
An important point to notice however, if that the only values of type 'a t for a t covariant in its first parameters are precisely those that does not contains any 'a. Thus, if I have a value of type 'a. 'a option, I know that I have in fact a None. We can in fact check that point with the help of the typechecker:
type forall_option = { x:'a. 'a option }
type void = |
let for_all_option_is_none {x} = match (x: void option) with
| None -> ()
| _ -> . (* this `.` means that this branch cannot happen *)
Here by constraining the type 'a. 'a option to void option, we have made the typechecker aware than x was in fact a None.
I am new to Ocaml. Here is one question in my class:
let f a b c d e = e.( if e.(1) then a b else b d )
We were asked to inferred the type of "a". I think it is an int, because this if operation should return an int to be the index of e array. But my answer is wrong. Can anyone help me to analyze this ? Thank you very much !
The value of the if is either a b or b d. Since the expression a b must return an int (as you say), a must be a function that accepts one argument and returns an int. So a is not an int but a function.
The type of the parameter of a is also part of the type of a. To determine this type, note that b is also a function that returns an int (as you can tell from the subexpression b d). So a is a function that accepts one argument that is a function and returns int. Since there is nothing in the code to limit the type of d, b can be any function that accepts one argument and returns an int. Let's call the type of b's argument 't. Note that this type can be different for different calls to f. So then the type of a is ('t -> int) -> int, where the corresponding type of b is 't -> int and the type of d is 't.
This is all pretty complicated. Possibly there's a typo in your transcription. Or maybe it's good to work out a complicated example :-)
the above statement is equivalent to:
fun f(a,b,c,d) = e[ if e[1] then a(b) else b(d) ]
__
Note:
"if e[1] then a(b) else b(d)" : this should be an int, as it act as the index of e array. function will return the same type, so Type of a(b) and b(d) are equal and should return integer.
e[1] = this should be boolean, that means e is an array of boolean.
Hence what we concluded
e : array of boolean
a : function returns an integer
b : function returns an integer.
we can't further type inference for c and d.
In OCaml, the inferred type of
let f = List.map fst
is
val f : ('_weak1 * '_weak2) list -> '_weak1 list = <fun>
while the inferred type of
let g x = List.map fst x
is
val g : ('a * 'b) list -> 'a list = <fun>
(types taken from utop).
As a result of this, f cannot be used polymorphically, while g can.
Why does this eta conversion between pure functions cause such a difference in type inference?
The difference is due to the value restriction, which does not allow the first definition to be polymorphic: it is defined by an application, which is not a value. The second form is defined as a function, which is a value. The notation '_weakN indicates a monomorphic type that is not yet resolved, as opposed to a polymorphic type variable like 'a.
See this chapter for more background.
Perhaps neither of these statements are categorically precise, but a monad is often defined as "a monoid in the category of endofunctors"; a Haskell Alternative is defined as "a monoid on applicative functors", where an applicative functor is a "strong lax monoidal functor". Now these two definitions sound pretty similar to the ignorant (me), but work out significantly differently. The neutral element for alternative has type f a and is thus "empty", and for monad has type a -> m a and thus has the sense "non-empty"; the operation for alternative has type f a -> f a -> f a, and the operation for monad has type (a -> f b) -> (b -> f c) -> (a -> f c). It seems to me that the real important detail is in the category of endofunctors versus over endofunctors, though perhaps the "strong lax" detail in alternative is important; but that's where I get confused because within Haskell at least, monads end up being alternatives: and I see that I do not yet have a precise categorical understanding of all the details here.
How can it be precisely expresseed what the difference is between alternative and monad, such that they are both monoids relating to endofunctors, and yet the one has an "empty" neutral and the other has a "non-empty" neutral element?
In general, a monoid is defined in a monoidal category, which is a category that defines some kind of (tensor) product of objects and a unit object.
Most importantly, the category of types is monoidal: the product of types a and b is just a type of pairs (a, b), and the unit type is ().
A monoid is then defined as an object m with two morphisms:
eta :: () -> m
mu :: (m, m) -> m
Notice that eta just picks an element of m, so it's equivalent to mempty, and curried mu becomes mappend of the usual Haskell Monoid class.
So that's a category of types and functions, but there is also a separate category of endofunctors and natural transformations. It's also a monoidal category. A tensor product of two functors is defined as their composition Compose f g, and unit is the identity functor Id. A monoid in that category is a monad. As before we pick an object m, but now it's an endofunctor; and two morphism, which now are natural transformations:
eta :: Id ~> m
mu :: Compose m m ~> m
In components, these two natural transformations become:
return :: a -> m a
join :: m (m a) -> m a
An applicative functor may also be defined as a monoid in the functor category, but with a more sophisticated tensor product called Day convolution. Or, equivalently, it can be defined as a functor that (laxly) preserves monoidal structure.
Alternative is a family of monoids in the category of types (not endofunctors). This family is generated by an applicative functor f. For every type a we have a monoid whose mempty is an element of f a and whose mappend maps pairs of f a to elements of f a. These polymorphic functions are called empty and <|>.
In particular, empty must be a polymorphic value, meaning one value per every type a. This is, for instance, possible for the list functor, where an empty list is polymorphic in a, or for Maybe with the polymorphic value Nothing. Notice that these are all polymorphic data types that have a constructor that doesn't depend on the type parameter. The intuition is that, if you think of a functor as a container, this constructor creates and empty container. An empty container is automatically polymorphic.
Both concepts are tied to the idea of a "monoidal category", which is a category you can define the concept of a monoid in (and certain other kinds of algebraic structures). You can think of monoidal categories as: a category defines an abstract notion of functions of one argument; a monoidal category defines an abstract notion of functions of zero arguments or multiple arguments.
A monad is a monoid in the category of endofunctors; in other words, it's a monoid where the product (a function of 2 arguments) and the identity (a function of 0 arguments) use the concept of multi-argument function defined by a particular (bizarre) monoidal category (the monoidal category of endofunctors and composition).
An applicative functor is a monoidal functor. In other words, it's a functor that preserves all the structure of a monoidal category, not just the part that makes it a category. It should be obvious that that means it has mapN functions for functions with any number of arguments, not just functions of one argument (like a normal functor has).
So a monad exists within a particular monoidal category (which happens to be a category of endofunctors), while an applicative functor maps between two monoidal categories (which happen to be the same category, hence it's a kind of endofunctor).
To supplement the other answers with some Haskell code, here is how we might represent the Day convolution monoidal structure #Bartosz Milewski refers to:
data Day f g a = forall x y. Day (x -> y -> a) (f x) (g y)
With the unit object being the functor Identity.
Then we can reformulate the applicative class as a monoid object with respect to this monoidal structure:
type f ~> g = forall x. f x -> g x
class Functor f => Applicative' f
where
dappend :: Day f f ~> f
dempty :: Identity ~> f
You might notice how this rhymes with other familiar monoid objects, such as:
class Functor f => Monad f
where
join :: Compose f f ~> f
return :: Identity ~> f
or:
class Monoid m
where
mappend :: (,) m m -> m
mempty :: () -> m
With some squinting, you might also be able to see how dappend is just a wrapped version of liftA2, and likewise dempty of pure.
I have this type, which defines an expression. I know that * symbol lets me add pairs, but what is the -> for?
# type expression = Value of float
| Sum of (expr*expr)
| Subtraction of (expr*expr)
| Fc1 of ((float->float)*expr)
The -> operator is for function types. a -> b means "a in, b out", so float -> float is the type of functions that take a float as their argument and produce a float as their result.
What about float -> float -> float
-> is right-associative, so a -> b -> c is the same as a -> (b -> c) meaning a function that takes an a and produces another function of type b -> c. Functions like this are often used to simulate multi-arguments functions (you can use f x y to apply f to x and then apply the resulting function to y, which effectively calls the inner function with two arguments) as an alternative to tuples. This way of simulating multi-argument functions is called currying.