Reputation: 1
I'm reviewing Haskell: The Craft of Functional Programming, however the type signatures on page 356 have thrown me for a loop.
Here is a simple one:
succeed :: b -> Parse a b
succeed val inp = [( val, inp )]
How can that be b -> Parse a b
, if
succeed Int -> Int
succeed a = a
and,
succeed Int -> Int -> Int
succeed a b = a + b
The amount of arguments your taking has to be in the type declaration right? How can you take val
, and imp
, if your type declaration only has one type variable: succeed :: b -> Parse a b
is supposed to read, take one variable of type a
and return a type of Parse a b
, not take two variables... where is inp
permitted?
Upvotes: 3
Views: 382
Reputation: 234424
In Haskell all functions take exactly one argument and produce exactly one result. When have a type like this a -> b -> c
you have the same as a -> (b -> c)
. So, instead of a two-argument function, you actually have a function that when given an argument produces another function that takes the second argument and produces the final result.
When you apply a function to two arguments, like this f x y
, it's the same as (f x) y
. You're actually applying the function that results from f x
to the second argument y
. From this behavior you get "partial application" for free.
There is a pair of functions in the Prelude named curry
and uncurry
that let you convert between functions written in this style and functions that take two arguments directly as a pair:
uncurry :: (a -> b -> c) -> ((a,b) -> c)
curry :: ((a,b) -> c) -> (a -> b -> c)
f :: a -> b -> c
f = ...
f' :: (a,b) -> c
f' = uncurry f
I don't know how Parse
was defined, but if you define it as a synonym to a function type (something common with parsers), you get that kind of behavior.
Upvotes: 1
Reputation: 1617
Because Parse
is a type synonym with ->
in its expansion. Example:
type Foo = Int -> Int
succeed :: Int -> Foo
succeed a b = a + b
Upvotes: 8