Home > Mobile >  Why is (&) :: a -> (a -> b) -> b not treated as Monad?
Why is (&) :: a -> (a -> b) -> b not treated as Monad?

Time:02-21

Mathematically, the binary operation for function application is an endo-Functor/Monad.

pipe :: (a -> b) -> a -> b
pipe = \f -> \a -> f a

(|>) :: a -> (a -> b) -> b
(|>) = flip pipe

infixl 1 |>

It's called pipeline-operator, and in Haskell, predefined as

https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Function.html#v:-38-

(&) :: a -> (a -> b) -> b

monadTestPipe :: IO ()
monadTestPipe = do
  "Monad Laws========" & print
  let i = id

  let a = (3 :: Int)
  let f = (\a -> a   1) >>> i
  let g = (\a -> a * 2) >>> i
  let m = f a -- 4
  "---------------------------------" & print
  do
    "-- Left/Center/Right identity" & print
    let lft = a & i & f
    let ctr = a & f -- = m
    let rit = a & f & i
    ---------------------------------
    lft & print -- 4
    ctr & print -- 4
    rit & print -- 4
    "---------------------------------" & print
  do
    "-- Associativity" & print
    -- m = f a -- 4
    (m & f) & g
      & print -- 10 = (4 1)x2
    m & (\x -> f x & g)
      & print -- 10
    "---------------------------------" & print

Why is the pipeline-operation (&) :: a -> (a -> b) -> b not treated (at least not integrated) as Monad in Haskell?

Or, it's probably fine to say, I've never read that in any Haskell wiki or books.

Edit: I want to make my question as concise as possible in order to prevent diffusion of issues, but

class Applicative m => Monad m where
  (>>=) :: m a -> (a -> m b) -> m b
  return :: a -> m a

>>= is simply a symbol of Monad type class in Haskell, and & can be integrated to >>= because & is a monad operator in mathematical sense.

return is id :: a -> a

CodePudding user response:

It is treated as the bind operation (aka (>>=)) of a monad (specifically the identity monad), just not directly. You must use a wrapper, due to the way the type system works: you cannot have a type synonym like type Id a = a as an instance of Monad and there are no type-level lambdas.

type Id a = a simply describes a synonym: a and Id a are the same type.

You cannot have an instance like

instance Monad Id

using the above definition of Id because Id is in essence the same as a type-level lambda \a -> a (if such a thing existed in Haskell), and Haskell doesn't have this kind of type-level lambda, since they would make Haskell's type system undecidable.

However, this is exactly one of the main reasons the newtype construct was created. It creates a new type (as its name suggests) which wraps the old type and only exists to distinguish between the old type and the new one at a type-level. They even have the same runtime representation. You can read more about the difference between the two here.

In this case, the wrapper is called Identity.

  • Related