How can I understand “(.) . (.)”?

前端 未结 5 1862
我寻月下人不归
我寻月下人不归 2020-12-08 00:40

I believe I understand fmap . fmap for Functors, but on functions it\'s hurting my head for months now.

I\'ve seen that you can just apply the definitio

5条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-08 01:17

    Your solution diverges when you introduce y. It should be

    \x f y -> ((.) ((.) x) f) y     :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    \x f y z -> ((.) ((.) x) f) y z :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    \x f y z -> ((.) x (f y)) z     :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    -- Or alternately:
    \x f y z -> (x . f y) z         :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    \x f y z -> (x (f y z))         :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    

    Which matches the original type signature: (.) . (.) :: (c -> d) -> (a -> b -> c) -> a -> b -> d

    (It's easiest to do the expansion in ghci, where you can check each step with :t expression)

    Edit:

    The deeper intution is this:

    (.) is simply defined as

    \f g -> \x -> f (g x)
    

    Which we can simplify to

    \f g x -> f (g x)
    

    So when you supply it two arguments, it's curried and still needs another argument to resolve. Each time you use (.) with 2 arguments, you create a "need" for one more argument.

    (.) . (.) is of course just (.) (.) (.), so let's expand it:

    (\f0 g0 x0 -> f0 (g0 x0)) (\f1 g1 x1 -> f1 (g1 x1)) (\f2 g2 x2 -> f2 (g2 x2))
    

    We can beta-reduce on f0 and g0 (but we don't have an x0!):

    \x0 -> (\f1 g1 x1 -> f1 (g1 x1)) ((\f2 g2 x2 -> f2 (g2 x2)) x0) 
    

    Substitute the 2nd expression for f1...

    \x0 -> \g1 x1 -> ((\f2 g2 x2 -> f2 (g2 x2)) x0) (g1 x1) 
    

    Now it "flips back"! (beta-reduction on f2):
    This is the interesting step - x0 is substituted for f2 -- This means that x, which could have been data, is instead a function.
    This is what (.) . (.) provides -- the "need" for the extra argument.

    \x0 -> \g1 x1 -> (\g2 x2 -> x0 (g2 x2)) (g1 x1) 
    

    This is starting to look normal... Let's beta-reduce a last time (on g2):

    \x0 -> \g1 x1 -> (\x2 -> x0 ((g1 x1) x2))
    

    So we're left with simply

    \x0 g1 x1 x2 -> x0 ((g1 x1) x2)
    

    , where the arguments are nicely still in order.

提交回复
热议问题