简体   繁体   中英

How does this Haskell code work? fmap fmap (,) <*> Just . reverse

Would someone help explain/breakdown the following code:

λ> fmap fmap (,) <*> Just . reverse $ "stackoverflow"
Just ("stackoverflow","wolfrevokcats")

It would be great if someone could walk me through their process of understanding the mechanics of this kind of code.

Let's try to decode this pointless style obfuscation:

fmap fmap (,) <*> Just . reverse $ "stackoverflow"

First step: how this is parsed? Well, $ has low precedence, so it's

(fmap fmap (,) <*> Just . reverse) $ "stackoverflow"

Also, I guess that the infix <*> has a lower precedence than . (one could check using the documentation or :i in GHCi). So, we get

((fmap fmap (,)) <*> (Just . reverse)) $ "stackoverflow"

Let's beta-reduce the $

((fmap fmap (,)) <*> (Just . reverse)) "stackoverflow"

So, the result of <*> is a function. This means that we are working in the (->) a applicative. There, (<*>) = \\xyz -> xz (yz) AKA the S combinator from lambda calculus. We can beta-reduce that:

(\z -> (fmap fmap (,)) z ((Just . reverse) z)) "stackoverflow"

More betas, removing parentheses when we can:

fmap fmap (,) "stackoverflow" ((Just . reverse) "stackoverflow")

More simplification:

fmap fmap (,) "stackoverflow" (Just (reverse "stackoverflow"))
fmap fmap (,) "stackoverflow" (Just "wolfrevokcats")

Now, the fmap fmap (,) part. The (,) argument is a function, so this means that the first fmap is working in the (->) a functor. There, fmap = (.) . So, it's just obfuscation for

(.) fmap (,) "stackoverflow" (Just "wolfrevokcats")
(fmap . (,)) "stackoverflow" (Just "wolfrevokcats")
(fmap ((,) "stackoverflow")) (Just "wolfrevokcats")
fmap ((,) "stackoverflow") (Just "wolfrevokcats")

Now, the second argument of fmap is of type Maybe String , so the fmap is working in the Maybe functor. There, fmap f (Just x) = Just (fx) . We get

Just (((,) "stackoverflow") "wolfrevokcats")
Just ((,) "stackoverflow" "wolfrevokcats")
Just ("stackoverflow", "wolfrevokcats")

Conclusion: pointless code is often pointless. To decode this snippet we had to run the type inferer in our head, recall three specific instances (even if they are pretty standard), and cope with precedence. No one should ever use this style except for deliberate obfuscation. (Surely not as a hiring puzzle!)

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