Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

difference between (a -> a) and a -> a

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

like image 764
maclunian Avatar asked May 03 '11 21:05

maclunian


3 Answers

(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.

like image 118
kennytm Avatar answered Oct 12 '22 19:10

kennytm


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 either x op y or y 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.

like image 4
Don Stewart Avatar answered Oct 12 '22 21:10

Don Stewart


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

like image 2
Dan Burton Avatar answered Oct 12 '22 19:10

Dan Burton