简体   繁体   中英

Associativity of ->

For monad bind operator, I can find that it's associativity is left from ghci using:

λ> :i (>>=)
class Monad (m :: * -> *) where
  (>>=) :: m a -> (a -> m b) -> m b
  ...
    -- Defined in ‘GHC.Base’
infixl 1 >>=

But the same doesn't work for -> :

λ> :i (->)
data (->) a b   -- Defined in ‘GHC.Prim’
instance Monad ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’

Where exactly it's associativity is documented (Link to Haskell report is welcome, but I was not able to find there in my attempt) ?

From the Haskell 2010 Language Report at §4.1.2 (Syntax of Types), page 38:

A function type has the form t1 -> t2 , which is equivalent to the type (->) t1 t2 . Function arrows associate to the right. For example, Int -> Int -> Float means Int -> (Int -> Float) .

Here you can find the context in the report:

图像显示了上面引用的上下文

The other answers apply to the standard language, in which -> is the only infix type operator and so may be considered pure syntax. However, GHC has the TypeOperators extension, so then it's a bit more subtle. From the manual :

  • Function arrow is infixr with fixity 0. (This might change; I'm not sure what it should be.)

Given this it might be considered a bug that it doesn't list the fixity with :i . (Edit: Made a ticket .)

The -> operator is right associative. Here is a place where that's documented: https://wiki.haskell.org/Partial_application

There are two reasons why :i (>>=) and :i (->) are different:

  • (>>=) is a function, but (->) can only occur in the type of a function
  • (>>=) is actually defined somewhere (for each Monad type), but (->) is built-in

Why does right associativity makes sense? Whenever a function has an argument which is a function itself, you want to make this explicit. Take for example "map":

:t map
map :: (a -> b) -> [a] -> [b]

Map is a function which takes two arguments, the first is of the type (a -> b), so it is clearly a function, and the second is of the type [a]. It returns [b]. We could of course (since -> is right-associative) read Map as having the type:

map :: (a -> b) -> ([a] -> [b])

While this is precisely the same type, we now read map as taking one argument, which is a function of the type (a -> b), and returning another function, which is of type ([a] -> [b]). These two ways to understand the type of map are described in the partial application article above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM