有人会帮助解释/细分以下代码:
0
如果有人能够指导我理解这种代码的机制,那将是很棒的。
答案 0 :(得分:10)
让我们尝试解码这种毫无意义的样式混淆:
fmap fmap (,) <*> Just . reverse $ "stackoverflow"
第一步:如何解析?好吧,$
的优先级很低,所以它是
(fmap fmap (,) <*> Just . reverse) $ "stackoverflow"
另外,我猜中缀<*>
的优先级低于.
(可以使用文档或GHCi中的:i
进行检查)。所以,我们得到
((fmap fmap (,)) <*> (Just . reverse)) $ "stackoverflow"
让我们降低$
((fmap fmap (,)) <*> (Just . reverse)) "stackoverflow"
因此,<*>
的结果是一个函数。这意味着我们正在使用(->) a
应用程序。在那里,(<*>) = \x y z -> x z (y z)
AKA是来自lambda演算的S组合子。我们可以通过beta减少:
(\z -> (fmap fmap (,)) z ((Just . reverse) z)) "stackoverflow"
更多测试版,在我们可以的时候删除括号:
fmap fmap (,) "stackoverflow" ((Just . reverse) "stackoverflow")
更简化:
fmap fmap (,) "stackoverflow" (Just (reverse "stackoverflow"))
fmap fmap (,) "stackoverflow" (Just "wolfrevokcats")
现在,fmap fmap (,)
部分。 (,)
参数是一个函数,因此这意味着第一个fmap
正在(->) a
仿函数中运行。那里,fmap = (.)
。所以,这只是
(.) fmap (,) "stackoverflow" (Just "wolfrevokcats")
(fmap . (,)) "stackoverflow" (Just "wolfrevokcats")
(fmap ((,) "stackoverflow")) (Just "wolfrevokcats")
fmap ((,) "stackoverflow") (Just "wolfrevokcats")
现在,fmap
的第二个参数的类型为Maybe String
,因此fmap
正在Maybe
仿函数中运行。那里,fmap f (Just x) = Just (f x)
。我们得到
Just (((,) "stackoverflow") "wolfrevokcats")
Just ((,) "stackoverflow" "wolfrevokcats")
Just ("stackoverflow", "wolfrevokcats")
结论:无意义的代码往往毫无意义。要解码这个片段,我们必须在头脑中运行类型推理器,回忆三个特定实例(即使它们非常标准),并应对优先级。除了故意混淆之外,没有人应该使用这种风格。 (当然不是招聘谜题!)