I am currently revising for my programming exam (I am new at programming) and I came across with an exercise asking me to implement a functions which "take a frequency tree and list of bits to a value in the Frequency tree and return the remaining bits in a list".
the part that i have trouble understanding is the type that I was given:
FreqTree a -> [bit] -> (a,[bit])
what does the (a, [bit]) actually mean? is a just a value?
Thanks heaps
The type (a, b) is a tuple or pair containing both an a and a b. In Haskell lowercase types are actually type variables, or unknowns. If they are written in a type then it means that the type is invariant to the actual type that variable represents.
If we read the description of this function carefully we can see it is reflective of the type:
take a frequency tree and list of bits to a value in the Frequency tree and return the remaining bits in a list
A function type like
a -> b -> c
can be read as a function from an a and a b to a c. In fact, to further cement the notion of and we had before we can write an equivalent function of type
(a, b) -> c
repeating the idea that tuple types should be read as "and". This conversion is called curry
curry :: (a -> b -> c) -> ((a, b) -> c)
curry f (a, b) = f a b
Using this notion, the description of the function translates to
(FreqTree, ListOfBits) -> (ValueInFreqTree, ListOfRemainingBits)
take
a frequency tree *and* list of bits
to
a value in the Frequency tree *and* the remaining bits in a list
From here we just do a little pattern matching against the type given
(FreqTree , ListOfBits) -> (ValueInFreqTree, ListOfRemainingBits)
FreqTree -> ListOfBits -> (ValueInFreqTree, ListOfRemainingBits)
FreqTree a -> [bit] -> (a , [bit] )
The first step above is the opposite of curry, called uncurry, and the second step compares our expected type to the type given. Here we can see some good parity—list of bits map to [bit] and FreqTree maps to FreqTree a.
So the final bit is to figure out how that type variable a works. This requires understanding the meaning of the parameterized type FreqTree a. Since frequency trees might contain any type of thing caring not about its particular form and only about the ability to compute its frequency, it's nice to parameterize the type by it's value. You might write
FreqTree value
where, again, the lowercase name represents a type variable. In fact, we can do this substitution in the previous type as well, value for a
FreqTree value -> [bit] -> (value, [bit])
and now perhaps this type has taken its most clear form. Given a FreqTree containing unknown types marked as value and a list of bit, we return a particular value and another list of bit.
Related
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.
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree;;
Is it a type definition, where a is a type parameter, and tree is the type name?
In Node of, is Node a built-in type of OCaml? What does of mean?
Thanks.
Yes 'a is a type parameter and tree is a type name (these are usually called variants in OCaml). This is reversed order from most other languages. Node is a constructor (called tag in OCaml) and of is just a keyword in OCaml to specify the types of the constructor arguments. Node is not a built-in type of OCaml (it is not even a type, but rather, as a I said, a constructor).
Hence Node (5, Empty, Node (6, Empty, Empty)) is something of type int tree (something like Tree<Int> in Java).
It may make more sense if you start with a simpler variant.
type shape = Square of int | Rectangle of int * int
Shape and Rectangle are tags (again constructors) that I have just made up that allow me to construct values of type shape (in this case I've chosen to have Shape take only one argument because only length is needed to specify a square, whereas Rectangles need both length and width). Nothing ever has a type of Shape or Rectangle, but things can have a type of shape.
One way to read that line in English is "I have defined a type called shape. A shape is either a Square of a single integer, or a Rectangle of two integers."
Now maybe for some reason I also want to label my shapes.
type 'label labelledshape = LabelledSquare of 'label * int | LabelledRectangle of 'label * int * int
The quote ' distinguishes that label is not a type (such as int), but is rather a variable. This allows me to write something like LabelledSquare ("a label for a square", 5) which is of type string labelledshape
Note that although this allows for polymorphism, these are not what is known as "polymorphic variants" in OCaml. I will not talk about that here, rather I'll just recommend either looking at OCaml documentation or browsing Stack Overflow for more details on that.
There are several kinds of type definitions:
Definition of a new sum type
From that type definition:
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree;;
Here are roughly the "facts" that the OCaml compiler knows about based on it:
tree is a unary type constructor. That means that for any type t, t tree is a type as well (example: int tree).
Empty is a 0-ary constructor for 'a tree. That means that Empty has type t tree for any t.
Node is a 3-ary constructor. Here this means that if a has type t, b has type t tree, and c has type t tree, then Node (a, b, c)has typet tree(note: that's the samet`)
those are the only two ways to have a value of type t tree. That means that you can use pattern matching (match ... with | Empty -> ... | Node (a, b, c) -> ...).
Definition of a type alias
A definition can also be something that looks like:
type t = existing_type
In that case, t is just a new neame for the existing_type.
For example:
type 'a pp = Format.formatter -> 'a -> unit
This means that something that is a int pp has type Format.formatter -> int -> unit.
This is the type of a function that takes a formatter and an integer and returns unit. Such as :
type 'a pp = Format.formatter -> 'a -> unit
module M : sig
val pp_int : int pp
end = struct
let pp_int fmt n = Format.fprintf fmt "%d" n
end
Let's consider a type t and two variables x,y of type t.
Will the call compare x y be valid for any type t? I couldn't find any counterexample.
The polymorphic compare function works by recursively exploring the structure of values, providing an ad-hoc total ordering on OCaml values, used to define structural equality tested by the polymorphic = operator.
It is, by design, not defined on functions and closures, as observed by #antron. The recursive nature of the definition implies that structural equality is not defined on values containing a function or a closure. This recursive nature also imply that the compare function is not defined on recursive values, as mentioned by a #antron as well.
Structural equality, and therefore the compare function and the comparison operators, is not aware of structure invariants and cannot be used to compare (mildly) advanced data structures such as Sets, Maps, HashTbls and so on. If comparison of these structures is desired, a specialised function has to be written, this is why Set and Map define such a function.
When defining your own structures, a good rule of thumb is to distinguish between
concrete types, which are defined only in terms of primitive types and other concrete types. Concrete types should not be used for structures whose processing expects some invariants, because it is easy to create arbitrary values of this type breaking these invariants. For these types, the polymorphic comparison function and operators are appropriate.
abstract types, whose concrete definition is hidden. For these types, it is best to provide specialised comparison function. The mixture library defines a compare mixin that can be used to derive comparison operators from the implementation of a specialised compare function. Its use is illustrated in the README.
It doesn't work for function types:
# compare (fun x -> x) (fun x -> x);;
Exception: Invalid_argument "equal: functional value".
Likewise, it won't (generally) work for other types whose values can contain functions:
# type t = A | B of (int -> int);;
type t = A | B of (int -> int)
# compare A A;;
- : int = 0
# compare (B (fun x -> x)) A;;
- : int = 1
# compare (B (fun x -> x)) (B (fun x -> x));;
Exception: Invalid_argument "equal: functional value".
It also doesn't (generally) work for recursive values:
# type t = {self : t};;
type t = { self : t; }
# let rec v = {self = v};;
val v : t = {self = <cycle>}
# let rec v' = {self = v'};;
val v' : t = {self = <cycle>}
# compare v v;;
- : int = 0
# compare v v';;
(* Does not terminate. *)
These cases are also listed in the documentation for compare in Pervasives.
I am attempting to multiply two int types in OCAML and I am not sure on what I might be doing wrong
let prime = Int64.of_string("0x100000002b2") in
let temp = ref prime in
hash := Int64.mul(!temp,prime);
I get the error
Error: This expression has type 'a * 'b
but an expression was expected of type int64
Any suggestions on how I can fix this ?
Update:
I got reference to this method from here
I am curious what this means
val mul : int64 -> int64 -> int64
Multiplication.
How do we know how many parameters this method takes ?
Function parameters in OCaml are (in the usual idiom) placed after the name of the function, with no parentheses and no comma.
# Int64.mul 8L 9L;;
- : int64 = 72L
Commas are used to create tuples, but Int64.mul doesn't accept a tuple. It accepts two separate arguments as above. (In FP parlance, it's a curried function.)
(It might be worth working through a short tutorial on OCaml. You seem to be assuming it's like traditional C family languages, but it's rather different.)
Update
The type x -> y is the type of a function that accepts a parameter of type x and returns a value of type y. The type x -> y -> z is the type of a (curried) function that takes two parameters of types x and y and returns a value of type z. (This is a somewhat simplified way of looking at things, but is close enough to get started with.)
So the function mul that you cite takes two parameters of type int64 and returns a value of type int64.
(I repeat my advice about an OCaml tutorial. It's really worth learning about the OCaml type system before getting too deep into coding.)
Why is the type of a plus ( + ) considered to be int -> int -> int as opposed to (int * int) -> int? To me, the second makes sense because it "accepts" a 2-tuple (the addends) and returns a single int (their sum).
Thank you!
You can make a language where (+) has the type (int * int) -> int. In fact, SML works exactly this way. It just affects the meaning of infix operators. However OCaml conventions strongly favor the use of curried functions (of the type a -> b -> c) rather than uncurried ones. One nice result is that you can partially apply them. For example ((+) 7) is a meaningful expression of type int -> int. I find this notation useful quite often.
This might seem a little unhelpful, but it's because the function takes two arguments.
When a function takes a tuple, it is in effect taking a single argument.
Because (+) is an inline function, taking a single argument would not be useful, as it would look like + (1,2) as opposed to 1 + 2.