Reputation: 14848
I'm looking through this introduction to Haskell which contains this example:
data Tree a = Leaf a | Branch (Tree a) (Tree a)
which it says is essentially also defining the types:
Branch :: Tree a -> Tree a -> Tree a
Leaf :: a -> Tree a
I understand the Leaf definition is saying that it maps an a
to a Tree
of a
. but I don't understand the Branch definition, I read it as "Branch maps Tree
of a
to Tree
of a
to Tree
of a
which doesn't sound correct. Is this because all Haskell functions get curried by default?
Upvotes: 3
Views: 2024
Reputation: 6463
I read it as "Branch maps Tree of a to Tree of a to Tree of a"
You can think of the definition as a function that takes a Tree a
and returns another function, which also takes a Tree a
and produces a Tree a
(which is the final result, a tree with two branches). Your signature of Branch
is equivalent to
Branch :: Tree a -> (Tree a -> Tree a)
The notion that every function has just one input parameter is called currying.
Upvotes: 3
Reputation: 476503
No. If it had a signature like:
Branch :: (Tree a, Tree a) -> Tree a
then you should have to feed it a tuple, and call the constructor like:
Branch (tree1,tree2)
Branch
has however a signature:
Branch :: Tree a -> Tree a -> Tree a
Or with explicit parenthesis:
Branch :: Tree a -> (Tree a -> Tree a)
So when you feed Branch
a first parameter, like Branch tree1
, the signature is:
(Branch t1) :: Tree a -> Tree a
when you finally feed it a second parameter t2
, its type will collapse to:
((Branch t1) t2) :: Tree a
A more convenient example is for instance (+)
which is not a constructor, but a function. (+)
our plus (+)
has signature
(+) :: Int -> Int -> Int
(Haskells plus is a bit more generic, but let's not consider this now).
If you now write (5+)
you have specialized your function to a function:
(5+) :: Int -> Int
In other words you constructed a new function that will add 5
to the given number.
Since the signatures for (a,b) -> c
and a -> b -> c
are however a bit equivalent, Haskell provides the curry
and uncurry
functions:
curry :: ((a, b) -> c) -> a -> b -> c
uncurry :: (a -> b -> c) -> ((a, b) -> c)
If you decide you need for instance an additional constructor for Branch
that should be fed a tuple, you can construct such constructor:
branchTuple :: (Tree a, Tree a) -> Tree a
branchTuple = uncurry Branch
Upvotes: 5
Reputation: 36375
Branch (Tree a) (Tree a)
is a constructor with two type parameters, both of which are Tree a
, and the result of that constructor is a Tree a
, hence the definition of
Tree a -> Tree a -> Tree a
I understand the Leaf definition is saying that it maps an a to a Tree of a. but I dont understand the Branch definition, shouldn't it be something like:
Branch :: (Tree a, Tree a) -> Tree a
No, because if you used (Tree a, Tree a)
, you would be defining a single type parameter which is a tuple.
Upvotes: 2