Composing function composition: How does (.).(.) work?

后端 未结 7 1617
温柔的废话
温柔的废话 2020-11-29 06:36

(.) takes two functions that take one value and return a value:

(.) :: (b -> c) -> (a -> b) -> a -> c

7条回答
  •  粉色の甜心
    2020-11-29 07:20

    Let’s ignore types for a moment and just use lambda calculus.

    • Desugar infix notation:
      (.) (.) (.)

    • Eta-expand:
      (\ a b -> (.) a b) (\ c d -> (.) c d) (\ e f -> (.) e f)

    • Inline the definition of (.):
      (\ a b x -> a (b x)) (\ c d y -> c (d y)) (\ e f z -> e (f z))

    • Substitute a:
      (\ b x -> (\ c d y -> c (d y)) (b x)) (\ e f z -> e (f z))

    • Substitute b:
      (\ x -> (\ c d y -> c (d y)) ((\ e f z -> e (f z)) x))

    • Substitute e:
      (\ x -> (\ c d y -> c (d y)) (\ f z -> x (f z)))

    • Substitute c:
      (\ x -> (\ d y -> (\ f z -> x (f z)) (d y)))

    • Substitute f:
      (\ x -> (\ d y -> (\ z -> x (d y z))))

    • Resugar lambda notation:
      \ x d y z -> x (d y z)

    And if you ask GHCi, you’ll find that this has the expected type. Why? Because the function arrow is right-associative to support currying: the type (b -> c) -> (a -> b) -> a -> c really means (b -> c) -> ((a -> b) -> (a -> c)). At the same time, the type variable b can stand for any type, including a function type. See the connection?

提交回复
热议问题