kjo*_*kjo 1 haskell functor algebraic-data-types bifunctor
假设这样定义了两个新类型
type MyProductType a = (FType1 a, FType2 a)
type MyCoproductType a = Either (FType1 a) (FType2 a)
Run Code Online (Sandbox Code Playgroud)
......那就是FType1并且Ftype2都是Functor.
如果现在要声明MyProductType并MyCoproductType作为实例Functor,编译器是否需要对各自fmap的定义进行明确定义,还是可以从之前的定义中推断出这些定义?
此外,这个问题的答案是依赖于实现的,还是来自Haskell规范?
作为背景,这个问题的动机是试图弄清楚我正在读的东西.作者首先定义
type Writer a = (a, String)
Run Code Online (Sandbox Code Playgroud)
...后来写道(我的重点)
...
Writer类型构造函数是functorial ina. 我们甚至不需要实现fmap它,因为它只是一种简单的产品类型.
强调的文字是我试图理解的评论.我认为这意味着哈斯克尔可以推断fmap的对任何基于函子类型ADT,并且,特别是它可以推断出fmap一个'简单的产品类型’之类Writer的,但现在我认为这种解释是不正确的(至少如果我正确阅读ØrjanJohansen的回答.
至于作者对那句话的意思,现在我真的不知道.也许所有他的意思是,Writer以这样一种方式重新定义以使其功能性可以被明确化是不值得的,因为它是如此"简单......类型".(抓住稻草在这里.)
首先,您通常不能为type同义词定义新实例,尤其是在您的情况下不需要部分应用的实例.我认为你的意思是定义一个newtype或data代替:
newtype MyProductType a = MP (FType1 a, FType2 a)
newtype MyCoproductType a = MC (Either (FType1 a) (FType2 a))
Run Code Online (Sandbox Code Playgroud)
标准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
Run Code Online (Sandbox Code Playgroud)
我们收到错误消息:
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’
Run Code Online (Sandbox Code Playgroud)
事实证明,GHC可以得出前三个,但不是最后一个.我相信第三个只能起作用,因为元组是特殊的.Either虽然不起作用,因为GHC没有保留关于如何Either对待它的第一个参数的任何特殊知识.它名义上是该论证中的数学函子,但不是Haskell Functor.
请注意,GHC更聪明地将变量仅用作已知为Functors 的类型的最后一个参数.以下工作正常:
newtype MyWrappedType a = MW (Either (FType1 Int) (FType2 (Maybe a))) deriving Functor
Run Code Online (Sandbox Code Playgroud)
总结一下:这取决于,GHC有一个扩展,但它并不总是聪明到做你想要的.