为什么没有`-XDeriveApplicative`扩展?

bga*_*ari 16 haskell ghc

GHC具有几个有用的语言的扩展,用于机械地导出各种常见的Haskell类型类(-XDeriveFunctor,-XDeriveFoldable,-XDeriveTraversable).似乎这Applicative是另一个经常需要并经常容易衍生出来的课程.对于包含类型插槽的简单记录a,例如,

data SimpleRecord a = Simple a a a
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

即使在稍微更难的情况下,某些a值被埋在其他应用程序中,例如,

data MyRecord f a = MyRecord (f a) a
Run Code Online (Sandbox Code Playgroud)

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

instance (Applicative f) => Applicative (MyRecord f) where
    pure x = MyRecord (pure x) x
    MyRecord a1 b1 <*> MyRecord a2 b2 = MyRecord (a1 <*> a2) (b1 b1)
Run Code Online (Sandbox Code Playgroud)

为什么-XDeriveApplicative不存在实现这些类型的机械实例的扩展?即使是derivegeneric-derive包装显然缺乏Applicative支持.有没有被有效期一般是一个理论问题排除这些情况下(超出也可能威胁到这些原因Functor,FoldableTraversable扩展)?

Jon*_*rdy 14

Functor对于给定数据类型,最多只有一个实例遵循仿函数定律.例如,mapfmap列表的唯一合法实现:

fmap id      == id
fmap (f . g) == fmap f . fmap g
Run Code Online (Sandbox Code Playgroud)

但是可以有不止一个守法的例子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
Run Code Online (Sandbox Code Playgroud)

对于列表,<*>可以表现得像\fs xs -> concatMap (\f -> map f xs) fs或类似zipWith ($),并且不清楚编译器应该选择哪一个.

  • 有许多方法可以推导出Ord,只要它很好地指明了派生的作用,那就不是问题了. (9认同)
  • @augustss:一个不同之处在于,在许多情况下,只要使用一致的顺序,使用什么顺序并不重要.与"Applicative"对比,它主要用于实例的实际属性. (7认同)
  • @bgamari实际上即使是"纯粹的"也不是毫不含糊的.对于列表`pure`的标准applicative functor给你一个单例列表,但为了使应用法则起作用,`ZipList``pure`必须给你注入值的无限重复列表!http://hackage.haskell.org/packages/archive/base/latest/doc/html/src/Control-Applicative.html#ZipList (5认同)
  • 同样的反对意见可用于反对`-XDeriveTraversable`,不是吗?"Traversable"定义指出这些动作应该"从左到右"排序,尽管我仍然觉得这并不总是清楚这意味着什么. (2认同)

scl*_*clv 7

为了回应别人,没有充分的理由我知道为什么我们不能拥有-XDeriveApplicative,我们根本就没有.通常有不止一个合法的实例FoldableTraversable,我们有一个标志来获得这些.有一段时间我们没有关于可穿越法律的真实好故事,但现在我们有了一些.同样,我们仍然没有Foldable法律(但我认为我们可以,见这里).

在不同的"明显"应用中,例如向前和向后的应用程序(对于<*>自身,甚至af a在有这样的情况下对多个进行置换),然后按照句法顺序遍历构建这里的应用程序,似乎合法.但是,对于诸如列表之类的递归类型,甚至是具有多个构造函数的类型,我们选择有效的应用程序都会以有趣的方式开花.对于类似列表的常规递归类型,明显的应用选择自然是"zipLike"一次,因为它以自然的方式推广非递归情况,将结构与结构匹配.对于具有多个构造函数的sum类型,"明显"选择更难定义.

在我看来,一个完全合理的applicative派生将按照这里的建议工作,在语法顺序上只有一个构造函数的类型(包括递归的).在多个构造函数的情况下,失败似乎是合法的.

另一方面,尽管Foldable和Traversable似乎经常出现在他们的"明显"形式中,但对于我来说,与有趣的相比,我们希望定义多少次"明显"的应用程序并不是很清楚.我的直觉告诉我,这个功能很少被运用,也许根本不常用.