考虑具有种类的类型* - > *,我正在努力寻找规则并建立直觉,以便何时能够以及何时无法使用Functor。
到目前为止,我看到的规则如下:
Functor
个实例
关于所包含的值。示例:Functor
您不能拥有Set
个实例,因为包含的值需要Ord
Functor
个实例。 示例:
newtype Contra a = Contra (a -> Int)
除此之外,还有其他情况吗?
答案 0 :(得分:5)
除了你的规则:
* -> *
Functor
实例。Functor
个实例。我想补充一点:
Functor
实例。例如data Iso a b = Iso (a -> b) (b -> a)
GADT通常不能有Functor
个实例。例如,
data Foo a where
Foo :: Foo Int
也许你会以某种方式想把它归结为只有协变的"以某种方式规则(我不清楚这甚至有什么差异),或者#34;不受限制的容器类型"某种程度上的规则(GADT引入了非常类似约束的类型等式)。
但是,请注意,这些规则仅适用于Functor
,而不适用于一般的仿函数。我希望你能做的任何愚蠢的类型(适当类型)都会成为与Hask密切相关的一些合适类别的算符。
答案 1 :(得分:5)
从类别理论的角度来看,类似*->*
的Haskell类型构造函数在Hask类别中定义了对象的映射(它是一个类别模数终止问题,我将方便地忽略)。仿函数是对象的映射,更重要的是,态射的映射。事实上,它主要是态射的映射 - 在某种程度上,对象的映射是其副作用。对象只是态射的终点。这种态射的映射必须保持构图和身份。
在Haskell中,态射是函数,函数的映射实现为fmap
。
在Haskell中,我们从对象的映射开始这一事实有点倒退。这是有效的,因为语言的语法极大地限制了定义对象映射的可能性。这种映射非常规则,并且通常配备有规范的函数映射。例如,代数数据类型是使用产品和副产品构建的,这些产品本质上是功能性的(因此自动deriving Functor
的可能性)。此外,函数类型(分类指数)在第二个参数中是functorial(在第一个参数中是逆变量)。因此,只要我们使用bicartesian封闭类别(产品,副产品和指数)的工具,就可以轻松构建对象的函数映射。
必须为给定类别中的每个对象定义仿函数,因此受类型类约束的数据类型(例如,Set
具有Ord
约束)不是Functor
s在Hask中,但它们可能是Hask子类别中的仿函数。 (可以在Haskell中使用自己的仿函数定义子类别。)
答案 2 :(得分:0)
Haskell用户指南中有-XDerivingFunctor
个扩展名。您可以找到完整说明here。它描述了函子派生可能失败的所有情况。这种描述有算法检查正确类型等的情况。但我相信这个算法的约束列表是详尽无遗的。
例如,另一种情况,当类型具有种类 * -> *
但不能是Functor
的实例时:
数据类型的最后一个类型变量用于-XExistentialQuantification约束,或者在GADT中进行细化