我想我发现了一个缺陷黑客文章Control.Applicative http://hackage.haskell.org/package/base-4.8.0.0/docs/Control-Applicative.html。
作为对应用函子定律的描述,它说:
class Functor f => Applicative f where
具有应用程序的函子,提供操作
嵌入纯表达式 (pure
),并进行序列计算并结合它们的结果(<*>
).
最小的完整定义必须包括满足以下定律的这些函数的实现:
identity
pure id <*> v = v
作品
pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
同态
pure f <*> pure x = pure (f x)
交换
u <*> pure y = pure ($ y) <*> u
(请注意,这并没有提及 fmap 的任何内容)并且它指出这些法律决定了Functor
实例:
由于这些法律,Functor
f 的实例将满足
fmap f x = pure f <*> x
起初我认为这显然是错误的。也就是说,我猜一定存在一个类型构造函数t
满足以下两个条件:
-
t
是一个实例Applicative
满足上述规则,并且
- 有两种不同的实现
instance (Functor t)
(即有两个不同的功能fmap1, fmap2 :: (a->b) -> (t a->t b)
,
满足函子定律)。
如果(且仅当)上述正确,则上述陈述must被重写为
f 的函子实例必须满足
fmap f x = pure f <*> x
作为这些法律的结果,这满足Functor
laws.
这显然是正确的,不管我的猜测正确与否.
我的问题是: 我的猜测正确吗?有没有t
具有所需的条件?
以下是我在尝试自己回答这个问题时的想法的解释。
如果我们只是数学家对实际的 Haskell 编程不感兴趣,我们可以很容易地肯定地回答这个问题。实际上,
t = Identity
newtype Identity a = Identity {runIdentity :: a}
满足上面的要求1和2(事实上,几乎任何事情都可以)。的确,Identity
是一个简单的例子Functor
and Applicative
,如定义Data.Functor.Identity http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Functor-Identity.html。 (这满足fmap f = (pure f <*>)
.)
定义另一个“实现”instance (Functor f)
, 采取, 对于每种类型a
, 两个函数
transf_a, tinv_a :: a -> a
这样
tinv_a . transf_a = id
(这是,理论上的设定, 简单的)。现在定义
instance (Functor Identity) where
fmap (f :: a->b) = Identity . transf_b . f . tinv_a . runIdentity
这满足Functor
法律,并且是一种与普通实施不同的实施,如果有的话
x :: a
f :: a -> b
这样
f x /= transf_b $ f $ tinv_a x
但我们是否可以在 Haskell 中做到这一点还不是很明显。是这样的:
class (Isom a) where
transf, tinv :: a -> a
instance (Isom a) where
transf = id
tinv = id
specialized instance (Isom Bool) where
transf = not
tinv = not
在哈斯克尔可能吗?
Edit
我忘记写一些非常重要的事情了。我认得Control.Applicative
作为 GHC 基础包的一部分,所以我也想知道我的问题的答案是否会随着任何 GHC 语言扩展而改变,例如FlexibleInstances
or OverlappingInstances
,我还不明白。