开发者

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

开发者 https://www.devze.com 2023-03-02 07:22 出处:网络
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 am

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 开发者_Python百科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 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.


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


This only makes a difference when you're making higher order functions. For example:

f :: a -> a -> b

is a function that expects two arguments of type a and return a value of type b, like so

f 2 2
f True True

But the function

f :: (a -> a) -> b

Expects a function as an argument. The only time where a -> a and (a -> a) are the same if they're the only argument in type inference, like here

f :: (a -> a)
-- Same type as
f :: a -> a

The rules for () in typing are pretty much the same as in normal expressions. It's like expressions a level above.


They are the same. Could you describe the errors you get when you use (a -> a)? It works fine for me with ghci-7.0.3:

Prelude> let f :: (a -> a); f = id
Prelude> f "foo"
"foo"
Prelude>

In general, you need to use parentheses in types when you're using functions as arguments. For example, map :: (a -> b) -> [a] -> [b]. Without the parens, it would mean something else.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号