为什么没有`

GHC有几种有用的语言扩展,用于机械派生各种常见的Haskell类型类( -XDeriveFunctor-XDeriveFoldable-XDeriveTraversable )。 看起来Applicative是另一类经常需要且经常容易派生的类。 对于包含类型a插槽的简单记录,例如,

data SimpleRecord a = Simple a a a

Applicative实例是平凡派生的,

instance Applicative SimpleRecord where
    pure x = Simple x x x
    Simple a1 b1 c1 <*> Simple a2 b2 c2 = Simple (a1 a2) (b1 b2) (c1 c2)

即使在一些稍硬的情况下a值都埋在其他应用性仿函数,例如,

data MyRecord f a = MyRecord (f a) a

一个合理的实例很容易写出来,

instance (Applicative f) => Applicative (MyRecord f) where
    pure x = MyRecord (pure x) x
    MyRecord a1 b1 <*> MyRecord a2 b2 = MyRecord (a1 <*> a2) (b1 b1)

为什么实现这些机械实例的-XDeriveApplicative扩展不存在? 即使derivegeneric-derive软件包显然缺乏Applicative支持。 是否有理论上的问题阻止这些实例通常是有效的(除了那些也可能威胁FunctorFoldable或可Traversable扩展的原因)?


对于给定的数据类型, Functor最多只有一个实例遵循函子法则。 例如, map是列表中fmap的唯一合法实现:

fmap id      == id
fmap (f . g) == fmap f . fmap g

但可以有一个以上的守法情况下Applicative ,这不一定是显而易见的。

pure id <*> v              == v
pure (.) <*> u <*> v <*> w == u <*> (v <*> w)
pure f <*> pure x          == pure (f x)
u <*> pure y               == pure ($ y) <*> u

对于列表, <*>行为可能像fs xs -> concatMap (f -> map f xs) fs或像zipWith ($) ,并且不清楚编译器应该选择哪一个。


为了呼应别人,我没有很好的理由知道为什么我们不能拥有-XDeriveApplicative ,我们只是碰巧不会。 通常有不止一个合法的FoldableTraversable实例,我们有一个标志来推导这些实例。 有一段时间,我们没有真正的可穿越法律的好故事,但现在我们有一些。 同样,我们还没有Foldable法律(但我认为我们可以,在这里看到)。

之间的不同的“明显的” applicatives,诸如向前和向后酮(相一相<*>本身,甚至置换相一相的多个afa ,如果有这样的),然后建立applicatives如这里提出,以遍历在句法顺序上,似乎是合法的。 但是,对于列表等递归类型,甚至包含多个构造函数的类型,我们选择的有效应用程序以有趣的方式开花。 对于列表式的常规递归类型,明显的应用选择自然是“zipLike”一次,因为它以自然的方式推广非递归的情况,将结构与结构进行匹配。 对于具有多个构造函数的求和类型,“明显”的选择很难定义。

在我看来,一个完全合理的应用派生将按照这里所建议的方式工作,只需要一个构造函数就可以按类型(包括递归)的语法顺序进行操作。 在多构造函数的情况下,失败似乎是合法的。

另一方面,尽管“可折叠”和“可穿越”似乎经常以其“明显”的形式出现,但对于我而言,与有趣的相比,我们有多少次想要定义“明显”应用。 我的直觉告诉我,这个功能很少会被使用,也许根本不经常使用。

链接地址: http://www.djcxy.com/p/43455.html

上一篇: Why is there no `

下一篇: Existential data types with a single strict field