I've noticed that (although I was once told that (a -> a)
and a -> a
meant the same thing), I get error messages when I use the (a -> a)
. Should I only use (a -> a)
when using brackets amongst the types? (i.e. (5 + 3)
instead of 5 + 3
)? Just not quite certain of when it's necessary
(a -> a)
and a -> a
are the same alone,
ff :: (a -> a) -- this compiles
ff = id
gg :: a -> a
gg = id
h :: a -> a -> Bool
h _ _ = True
i = h ff gg -- this compiles => ff & gg are of the same type.
but will be different when combined with more types like:
a -> a -> b
(a -> a) -> b
This is because ->
is right-associative, so a -> a -> b
actually means a -> (a -> b)
(take an a
and return a function), which is different from (a -> a) -> b
(take a function and return a b
).
This is like (1+2)*3
is different from 1+2*3
.
Parenthesization disambiguates several constructs in Haskell, when other information available to the compiler doesn't help:
Application associates to the left
so you can omit parens on function arguments.
Expressions involving infix operators are disambiguated by the operator's fixity.
so no need for parens in many cases with binary operators of different fixity.
Consecutive unparenthesized operators with the same precedence must both be either left or right associative to avoid a syntax error.
and finally:
Given an unparenthesized expression
x op y op z
, parentheses must be added around eitherx op y
ory op z
, unless certain conditions about precendence hold
My general advice, if the above statements don't make any sense: over-parenthesize things, until you learn the rules. Or, study the Haskell Report very hard.
Consider the expression 10 / 2 / 5
. Is that the same as (10 / 2) / 5
or 10 / (2 / 5)
? If you interpret /
to be mathematical division, then the former is true, while the latter is false. So you see, the answer to your question is "there is a difference, but only sometimes".
Types are the opposite. a -> b -> c
is the same as a -> (b -> c)
, and definitely not the same as (a -> b) -> c
.
You say you're not quite sure when it's necessary: well here it is. When the argument to your function is also a function, then it is necessary.
Consider map :: (a -> b) -> [a] -> [b]
. This is different than a -> b -> [a] -> [b]
, for you see, (a -> b)
indicates a specific kind of function: a function from type a
to type b
.
iterate :: (a -> a) -> a -> [a]
is more interesting. This function requires that the input and output types of the function in the first parameter must be the same.
You may be interested in reading up on currying and partial application. One good resource among many: Learn you a Haskell # Curried Functions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With