1

假设两个新类型是这样定义的

type MyProductType a = (FType1 a, FType2 a)

type MyCoproductType a = Either (FType1 a) (FType2 a)

……那FType1andFtype2都是Functor.

如果现在要声明MyProductTypeandMyCoproductType作为 的实例Functor,编译器是否需要为它们各自fmap的 's 明确定义,还是可以从以前的定义中推断出这些定义?

另外,这个问题的答案是依赖于实现的,还是遵循 Haskell 规范?


作为背景,这个问题的动机是试图理解我正在阅读的内容中的一句话。作者首先定义

type Writer a = (a, String)

...然后写(我的重点)

...Writer类型构造函数在a. 我们甚至不需要实现fmap它,因为它只是一个简单的产品类型。

强调的文字是我试图理解的评论。我认为这意味着 Haskell 可以根据函数类型推断任何fmapADT 的's ,特别是,它可以推断“简单产品类型”之类的我正在正确阅读Ørjan Johansen的答案)。fmapWriter

至于作者那句话是什么意思,现在我真的不知道了。也许他的意思是,不值得费心地重新定义Writer它的功能性可以明确,因为它是一种“简单......类型”。(在这里抓住稻草。)

4

1 回答 1

6

首先,您通常不能为type同义词定义新实例,尤其是在您的案例中需要的部分应用实例。我认为你的意思是定义一个newtypeordata代替:

newtype MyProductType a = MP (FType1 a, FType2 a)
newtype MyCoproductType a = MC (Either (FType1 a) (FType2 a))

标准 Haskell 根本没有提到Functor自动派生,这只能通过 GHC 的DeriveFunctor扩展来实现。(或者有时GeneralizedNewtypeDeriving,但这不适用于您的示例,因为您没有将a其用作构造函数中的最后一个参数。)

所以让我们试试:

{-# LANGUAGE DeriveFunctor #-}
data FType1 a = FType1 a deriving Functor
data FType2 a = FType2 a deriving Functor
newtype MyProductType a = MP (FType1 a, FType2 a) deriving Functor
newtype MyCoproductType a = MC (Either (FType1 a) (FType2 a)) deriving Functor

我们收到错误消息:

Test.hs:6:76:
    Can't make a derived instance of ‘Functor MyCoproductType’:
      Constructor ‘MC’ must use the type variable only as the last argument of a data type
    In the newtype declaration for ‘MyCoproductType’

事实证明,GHC 可以推导出三个,但不能推导出最后一个。我相信第三个之所以有效,是因为元组是特殊情况的。Either但不起作用,因为 GHC 没有保留任何关于如何Either处理其第一个参数的特殊知识。它名义上是该论点中的数学函子,但不是Haskell Functor

请注意,GHC 在仅将变量用作已知为Functors 的类型的最后一个参数方面更聪明。以下工作正常:

newtype MyWrappedType a = MW (Either (FType1 Int) (FType2 (Maybe a))) deriving Functor

所以总结一下:这取决于,GHC 对此有一个扩展,但它并不总是足够聪明地做你想做的事。

于 2015-09-20T15:13:59.093 回答