当你 can/cannot 有一个数据类型的 Functor 实例时是什么情况?
What are the situations when you can/cannot have a Functor instances for a datatype?
考虑一个类型为 * -> * 的类型,我正在尝试寻找规则并建立直觉,以确定何时可以和何时不能为该类型使用 Functor。
到目前为止,我看到的规则如下:
- 没有
Functor
有限制的容器类型的实例
关于包含的值。
示例:Set
不能有 Functor
实例,因为包含的值
需要 Ord
- 没有
Functor
逆变数据类型的实例。
示例:
newtype Contra a = Contra (a -> Int)
除此之外,还有其他情况吗?
除了您的规则:
- 必须友善
* -> *
- 没有
Functor
容器类型的实例对包含的值有限制。
- 没有
Functor
逆变数据类型的实例。
我要补充几点:
- "not for contravariant types" 的自然扩展:没有
Functor
不变数据类型的实例。例如data Iso a b = Iso (a -> b) (b -> a)
GADT 通常不能有 Functor
个实例。例如,
data Foo a where
Foo :: Foo Int
也许你会想以某种方式将其混入 "only covariant" 规则(我不清楚这甚至有什么差异),或者以某种方式将 "unrestricted container types" 规则(GADT 引入类型等式非常像约束)。
但是,请记住,这些规则仅适用于 Functor
,不适用于一般的函子。我希望你可以编写的任何愚蠢类型(适当的类型)都将成为与 Hask 密切相关的某个适当类别的函子。
Haskell 用户指南中有 -XDerivingFunctor
扩展。您可以找到完整的描述 here。它描述了仿函数推导可能失败的所有情况。这个描述有算法检查正确种类等的情况。但我相信这个算法约束列表是详尽无遗的。
例如,另一种情况,当 type 具有 kind * -> *
但不能是 Functor
的实例时:
A data type’s last type variable is used in an -XExistentialQuantification constraint, or is refined in a GADT
从范畴论的角度来看,Haskell的类型构造函数*->*
定义了一个对象的映射在范畴Hask中(这是一个类别模终止问题,我将方便地忽略它)。函子是对象的映射,更重要的是,态射的映射。事实上,它主要是态射的映射——对象的映射在某种程度上是它的副作用。对象只是态射的端点。这种态射映射必须保持组合和同一性。
在Haskell中,态射是函数,函数的映射实现为fmap
。
在 Haskell 中我们从对象映射开始的事实有点倒退。这是可行的,因为语言的语法极大地限制了定义对象映射的可能性。这样的映射非常规则,并且经常配备函数的规范映射。例如,代数数据类型是使用产品和副产品构造的,它们本质上是函子的(因此 deriving Functor
自动的可能性)。此外,函数类型(分类指数)在第二个参数中是函子的(在第一个参数中是逆变的)。所以,只要我们使用双笛卡尔闭范畴的工具(乘积、余积、指数),就很容易构造出对象的函子映射。
必须为给定类别中的每个对象定义函子,因此受类型 类 约束的数据类型(例如,具有 Ord
约束的 Set
)不是Functor
s 在 Hask 中,但它们可能是 Hask 子类别中的函子。 (可以在 Haskell 中定义子类别及其自己的函子。)
考虑一个类型为 * -> * 的类型,我正在尝试寻找规则并建立直觉,以确定何时可以和何时不能为该类型使用 Functor。
到目前为止,我看到的规则如下:
- 没有
Functor
有限制的容器类型的实例 关于包含的值。
示例:Set
不能有 Functor
实例,因为包含的值
Ord
- 没有
Functor
逆变数据类型的实例。
示例:
newtype Contra a = Contra (a -> Int)
除此之外,还有其他情况吗?
除了您的规则:
- 必须友善
* -> *
- 没有
Functor
容器类型的实例对包含的值有限制。 - 没有
Functor
逆变数据类型的实例。
我要补充几点:
- "not for contravariant types" 的自然扩展:没有
Functor
不变数据类型的实例。例如data Iso a b = Iso (a -> b) (b -> a)
GADT 通常不能有
Functor
个实例。例如,data Foo a where Foo :: Foo Int
也许你会想以某种方式将其混入 "only covariant" 规则(我不清楚这甚至有什么差异),或者以某种方式将 "unrestricted container types" 规则(GADT 引入类型等式非常像约束)。
但是,请记住,这些规则仅适用于 Functor
,不适用于一般的函子。我希望你可以编写的任何愚蠢类型(适当的类型)都将成为与 Hask 密切相关的某个适当类别的函子。
Haskell 用户指南中有 -XDerivingFunctor
扩展。您可以找到完整的描述 here。它描述了仿函数推导可能失败的所有情况。这个描述有算法检查正确种类等的情况。但我相信这个算法约束列表是详尽无遗的。
例如,另一种情况,当 type 具有 kind * -> *
但不能是 Functor
的实例时:
A data type’s last type variable is used in an -XExistentialQuantification constraint, or is refined in a GADT
从范畴论的角度来看,Haskell的类型构造函数*->*
定义了一个对象的映射在范畴Hask中(这是一个类别模终止问题,我将方便地忽略它)。函子是对象的映射,更重要的是,态射的映射。事实上,它主要是态射的映射——对象的映射在某种程度上是它的副作用。对象只是态射的端点。这种态射映射必须保持组合和同一性。
在Haskell中,态射是函数,函数的映射实现为fmap
。
在 Haskell 中我们从对象映射开始的事实有点倒退。这是可行的,因为语言的语法极大地限制了定义对象映射的可能性。这样的映射非常规则,并且经常配备函数的规范映射。例如,代数数据类型是使用产品和副产品构造的,它们本质上是函子的(因此 deriving Functor
自动的可能性)。此外,函数类型(分类指数)在第二个参数中是函子的(在第一个参数中是逆变的)。所以,只要我们使用双笛卡尔闭范畴的工具(乘积、余积、指数),就很容易构造出对象的函子映射。
必须为给定类别中的每个对象定义函子,因此受类型 类 约束的数据类型(例如,具有 Ord
约束的 Set
)不是Functor
s 在 Hask 中,但它们可能是 Hask 子类别中的函子。 (可以在 Haskell 中定义子类别及其自己的函子。)