简介:
我理解Maybe a
和Maybe Int
之间的区别,我也理解Either a b
和Either Int Int
之间的区别。我也理解Either Int
与Maybe
是同一种动物,它们都将一个类型作为参数并生成一个新类型,即它们都是类型构造函数,它们将一个类型作为参数(或者具体如Int或不具体如a
),并产生具体类型或多态类型。
现在我不明白的是Either a
是什么类型的结构?它不像Maybe
,因为如果我们向它提供具体类型(如Int
),它就永远不会产生具体的(读取非多态)类型。所以在这种情况下,调用Either a
多态类型构造函数并调用Maybe
具体类型构造函数是正确的吗? (这就是我如何称呼它们,它们在Haskell命名法中的正式名称是什么?)
此外,我不知道像Either a
这样的类型构造函数的Haskell类型系统中的官方分类是什么,因为它不能与Maybe
属于同一类别,因为 - 如上所述上一段 - 无论我们应用什么类型Either a
,结果类型永远不会是具体类型,即它始终是多态类型,例如Either a Int
。
我之所以这样问是因为Either a
是Functor
。这开始变得令人困惑。没有像我以前见过的任何东西。我不知道我应该如何在概念上解释Either a
(多态类型构造函数)是Functor
的实例这一事实?同样,(->) r
(也是与Either a
相同的动物)也是Functor
。
问题:
什么是Either a
和(->) r
?
他们正式称什么?
它们如何在概念上适合Haskell的类型系统?
这些多态类型构造函数在哪里更详细地描述/讨论?
我读到了什么,所以我对它们有了更好的理解?
我应该阅读有关种类的内容吗?类型是理解像Either a
和(->) r
这样的多态类型构造函数的秘密方式吗?
Either a Int
与[a]
是同一种动物吗?
Either a Int
的唯一目的是为函数声明多态输入和输出类型,就像[a]
中fmap :: (a -> b) -> [a] -> [b]
的情况一样?
最重要的问题:
我应该如何根据上述想法解释以下代码?
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
class Functor f where
fmap :: (a -> b) -> f a -> f b
结果fmap
函数(类型为fmap :: (a -> b) -> Either c a -> Either c b
)在c
中会是多态的吗?
这是使Either a
成为Functor
个实例的唯一效果吗?
因此,fmap
生成的c
函数将是多态的?
与相比,例如,将Either Int
设为Functor
的实例?
然后生成的fmap
仅适用于Either Int a
类型,但在所有Either a b
类型上不能正常/多态地工作?
如果我理解正确这是拥有像Either a
这样的多态类型构造函数的唯一目的和目的吗?那么fmap
适用于所有Either a b
类型?
我很困惑,我不确定我是否正确解释Either a
。有人可以确认1)我的解释是正确的2)如果没有那么请赐教我。
感谢阅读。
答案 0 :(得分:11)
Either a
实际上并没有这样的事情。与多态函数一样,多态实例应该通过通用量化来读取系统-F样式:
forall a . instance Functor (Either a) where ...
仿函数实例本身是一个字典,即类型级函数
functor = Λf -> { Λa b -> (a->b) -> f a->f b }
所以这两个实例都会像
eitherFunctor = Λa -> functor (Either a)
或者,您可以将其视为编译器将instance Functor (Either a)
替换为大量离散实例
instance Functor (Either ()) where ...
instance Functor (Either Int) where ...
...
instance Functor (Either (Either Int String)) where ...
...
虽然显然不可能这样做,但字面上。
答案 1 :(得分:1)
我不知道你的一些问题的答案 - 比如,某些事情被正式称为什么,或者在哪里阅读它们,因为在学习类型系统后它们对我来说是不言而喻的。 (这不应被视为一种建议,唯一的方法是获得研究依赖类型系统。)
Either Int
也可以声明为Functor
,但我们可以表达一个更一般的陈述,Either
的第一个参数是{{Int
实际上并不重要{1}} - 因此,我们声明Either a
是Functor
。
在其他类型的系统中,无需区分kinds
,而Either
也可以被视为一种类型;但是在Haskell中,它们与类型分开处理以简化类型系统。 Kinds
是一种描述类型具有arity并通过仅区分arity来避免依赖类型的复杂化的方法。因此,Either
和(->)
有2个,或kind
*->*->*
。
Either a Int
与[a]
的动物相同,因为它们的种类为*
。
fmap :: (a->b) -> Either c a -> Either c b
在c
中是多态的。此声明的重要性在于保留 c
。当然,对于任何类型c
,唯一的方法就是Left x
保持不变。
答案 2 :(得分:1)
Maybe
不是一种类型。 Maybe Int
是一种类型。但Maybe
本身就是你可以制作出类型的东西。它是类型的构造函数。
Either
不是类型,它是一个类型构造函数。你知道如何理解Haskell函数吗?好吧,你也可以讨论类型构造函数。所以Either
是一个2参数类型的构造函数,但Either Int
是一个1参数类型的构造函数。而Either Int Bool
是一种实际类型。
Functor
类型类是更高级的类型类。 Show
之类的内容适用于类型; Functor
适用于类型构造函数。例如,你不写
instance Functor (Maybe Int) where ...
相反,你写了
instance Functor (Maybe) where ...
Functor
的定义是
class Functor f where
fmap :: (x -> y) -> f x -> f y
此处f
不是类型,而是1参数类型构造函数。你给它一个参数(比如x
或y
)来构造一个真实的,可用的类型。
值包含“类型”。类型签名中的东西有“种类”。 “类型”有类*
。 “1参数类型构造函数”具有种类“* - > *”。它基本上说明了为获得实际类型需要提供多少参数。
总之,您可以为Functor (Either Int)
编写实例。但那时只允许Int
;通过使它成为一个类型变量,你可以使它更具多态性。
请注意,如果你想要它,那么Either
的第二个参数是固定的而不是第一个...你不能这样做。从某种意义上说,更高级的类型类别有点像kludge。它们很容易理解,它们适用于简单的案例。功能依赖关系和关联类型是两种(不兼容)尝试更好地解决此问题。