关于为 ADT 推断 fmap
On inferring fmap for ADTs
假设两个新类型是这样定义的
type MyProductType a = (FType1 a, FType2 a)
type MyCoproductType a = Either (FType1 a) (FType2 a)
...并且 FType1
和 Ftype2
都是 Functor
.
的实例
如果现在将 MyProductType
和 MyCoproductType
声明为 Functor
的实例,编译器是否 需要 为它们各自的显式定义fmap
的,或者它能从前面的定义中推断出这些定义吗?
此外,这个问题的答案是依赖于实现的,还是遵循 Haskell 规范?
作为背景,这个问题的动机是试图理解 something I'm reading 中的一句话。笔者首先定义
type Writer a = (a, String)
...后来写(我的重点)
...the Writer
type constructor is functorial in a
. We don't even have to implement fmap
for it, because it's just a simple product type.
强调的文字是我试图理解的评论。我 认为 这意味着 Haskell 可以根据函子类型为 any ADT 推断 fmap
,并且,在特别是,它可以推断 fmap
为 "simple product type",如 Writer
,但现在我认为这种解释是不正确的(至少如果我正确阅读 Ørjan Johansen 的回答)。
至于作者那句话是什么意思,我现在真的是一头雾水。也许他的意思是,不值得费心重新定义 Writer
,使其函子性可以明确,因为它就是这样一个 "simple ... type"。 (在这里抓住救命稻草。)
首先,您通常不能为 type
同义词定义新实例,尤其是您的情况需要的部分应用实例。我想你是想定义一个 newtype
或 data
来代替:
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
如何处理其 first 参数的特殊知识。它名义上是该参数中的 数学函子 ,但不是 Haskell Functor
.
请注意,GHC 更聪明地使用变量作为已知类型的最后一个参数 Functor
s。以下工作正常:
newtype MyWrappedType a = MW (Either (FType1 Int) (FType2 (Maybe a))) deriving Functor
所以总结一下:这取决于,GHC 对此有一个扩展,但它并不总是足够聪明来做你想做的事。
假设两个新类型是这样定义的
type MyProductType a = (FType1 a, FType2 a)
type MyCoproductType a = Either (FType1 a) (FType2 a)
...并且 FType1
和 Ftype2
都是 Functor
.
如果现在将 MyProductType
和 MyCoproductType
声明为 Functor
的实例,编译器是否 需要 为它们各自的显式定义fmap
的,或者它能从前面的定义中推断出这些定义吗?
此外,这个问题的答案是依赖于实现的,还是遵循 Haskell 规范?
作为背景,这个问题的动机是试图理解 something I'm reading 中的一句话。笔者首先定义
type Writer a = (a, String)
...后来写(我的重点)
...the
Writer
type constructor is functorial ina
. We don't even have to implementfmap
for it, because it's just a simple product type.
强调的文字是我试图理解的评论。我 认为 这意味着 Haskell 可以根据函子类型为 any ADT 推断 fmap
,并且,在特别是,它可以推断 fmap
为 "simple product type",如 Writer
,但现在我认为这种解释是不正确的(至少如果我正确阅读 Ørjan Johansen 的回答)。
至于作者那句话是什么意思,我现在真的是一头雾水。也许他的意思是,不值得费心重新定义 Writer
,使其函子性可以明确,因为它就是这样一个 "simple ... type"。 (在这里抓住救命稻草。)
首先,您通常不能为 type
同义词定义新实例,尤其是您的情况需要的部分应用实例。我想你是想定义一个 newtype
或 data
来代替:
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
如何处理其 first 参数的特殊知识。它名义上是该参数中的 数学函子 ,但不是 Haskell Functor
.
请注意,GHC 更聪明地使用变量作为已知类型的最后一个参数 Functor
s。以下工作正常:
newtype MyWrappedType a = MW (Either (FType1 Int) (FType2 (Maybe a))) deriving Functor
所以总结一下:这取决于,GHC 对此有一个扩展,但它并不总是足够聪明来做你想做的事。