我想我在hackage文章中Control.Applicative
发现了一个缺陷.作为应用仿函数法的描述,它说:
Run Code Online (Sandbox Code Playgroud)class Functor f => Applicative f where
带有应用程序的仿函数,提供嵌入纯表达式(
pure
)和序列计算的操作,并组合它们的结果(<*>
).最小完整定义必须包括满足以下法则的这些函数的实现:
身分
Run Code Online (Sandbox Code Playgroud)pure id <*> v = v
组成
Run Code Online (Sandbox Code Playgroud)pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
同态
Run Code Online (Sandbox Code Playgroud)pure f <*> pure x = pure (f x)
互换
Run Code Online (Sandbox Code Playgroud)u <*> pure y = pure ($ y) <*> u
(请注意,这并未说明有关fmap的任何内容)并且它声明这些法律确定了Functor
实例:
作为这些法律的结果,
Functor
f 的实例将满足Run Code Online (Sandbox Code Playgroud)fmap f x = pure f <*> x
我一开始以为这显然是错的.也就是说,我猜测必须存在t
满足以下两个条件的类型构造函数:
t
是一个 …在Haskell中,我们可以使用这个有用的习惯用法从列表中获取索引元素:
indexify :: (Num i) => [a] -> [(i,a)]
indexify = zip [0..]
Run Code Online (Sandbox Code Playgroud)
然而,根据实施zip
中GHC.List
作为base-4.9.1.0
,这将不能完全执行的操作列表的融合,即,这实际上不会产生列表[0 ..],但参数列表indexify
将被构造.
当然,有一个允许适当的列表融合的定义:
indexify' :: (Num i) => [a] -> [(i,a)]
indexify' xs = build $ \c n ->
foldr (\x r !i -> (i,x) `c` r (i+1)) (const n) xs 0
Run Code Online (Sandbox Code Playgroud)
我们需import GHC.Prim (build)
要这样做吗?或者是否有其他实现简化为indexify'
?