haskell fmap。 fmap函数,函数超过两个仿函数

时间:2015-05-10 16:23:06

标签: haskell

我发现自己越来越多地经常这样做......

我有一个函数f :: IO [a],然后我想在其上应用g :: a -> b类型的函数,以获取IO [b]

漫长的道路是:

x <- f
let y = fmap g x

然后我缩短为:

x <- f
let y = g <$> x

现在我宁愿这样做:

y <- fmap g <$> f

然后根据Functor法律,我可以看到我甚至可以做到:

(<$$>) = fmap . fmap
y <- g <$$> f

虽然我经常提到这个fmap . fmap,但我发现它在基础库中没有特殊的约束,而对我来说它似乎是一个非常频繁的习语。我真的可以在这个地方使用它!所以现在我想知道,我是不是都在努力编写纯粹的代码,这就是为什么我要比这更有经验的haskell程序员更多地尝试...或者是否有一种更优雅的方式来实现这一点,这就解释了为什么这个成语是其他人没有使用过吗?

4 个答案:

答案 0 :(得分:9)

我认为(在Haskell社区的各个部分中似乎相当不受欢迎)您应该编写代码以清楚地表达您的意图并遵循读者的期望,并且然后用代数法将你的代码重构为一个等价的形式,这个形式是&#34; neater&#34;,但不是更清楚。

在这种情况下,这里有两次出现的fmap似乎没有任何实际意义。您正在调整IO操作的结果这一事实在逻辑上并不符合调整恰好映射到列表的事实。如果您看到&#34; fmap . fmap模式&#34;很多时候,在你的代码中,这只是因为fmap是一个非常常见的功能。

如果你写

    y <- g <$$> x      -- or any other made-up operator name

你不仅强迫你的读者学习一个不熟悉的操作员,而且一旦他们学会了它,他们必须将它扩展到y <- fmap g <$> x,以便了解发生了什么,因为你将两个不相关的操作组合在一起。 / p>

最佳形式是y <- fmap g <$> x(甚至更好,y <- map g <$> x),因为它符合熟悉的模式var <- function <$> action

(顺便说一句,你提到了Functor法律,但它们与你问题中的任何重写都没有关系,这只是扩展定义。)

答案 1 :(得分:4)

那么,你有什么组成的仿函数。这个概念最普遍的实现 - 虽然不像你想的那么普遍 - 是 monad变形金刚

http://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-Trans-List.html#v:ListT

f' :: ListT IO a
f' = ListT f

在此之后,您只需使用fmap g,即可获得h' :: ListT IO b的值runListT,然后将其评估为IO [b]

包装和展开是否值得取决于您连续执行的操作数量,可以使用相同的组合。对于某些应用,monad变压器非常棒;在其他情况下,他们只是制造比现在更笨重的东西。 fmap . fmap实际上并不太糟糕,是吗?我常常只是坚持下去。

答案 2 :(得分:4)

Functors(和applicatives)组成,documentation for glBlendEquation定义两个仿函数组合的仿函数和应用实例。这意味着您可以将IO [a]包裹在Compose IO [] a中并应用fmap,例如

import Data.Functor.Compose
getCompose $ fmap g $ Compose f

答案 3 :(得分:2)

我发现自己经常这样做并且发现它真的很混乱。我发现liftM . mapfmap . fmap更容易阅读。

相关问题