将 Either 理解为函子
Understand Either as a Functor
查看 Either 是如何定义为函子的,我可以看到
derive instance functorEither :: Functor (Either a)
这对我来说是“你可以 map
一个 Either 只要你可以 map
它的元素。
但两者都不只有一个元素。如果没有 derive
,这将如何实现?这是我尝试过的:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
当然,类型在这里不起作用:
右边有这个签名:map :: forall a b. (a -> b) -> f a -> f b
然而,左派不行:map :: forall a b. (a -> b) -> f a -> f a
我的部分直觉是 Either a b
不是函子,只有 Either a
是函子。这就是为什么 map
对 Right
有效并忽略 Left
这并没有真正让我对它的实现方式有任何直觉。我仍然需要一种匹配两个构造函数的方法,不是吗?
另一方面,我认为用 identity
替换内部函数的 map
的实现在技术上对仿函数来说是守法的吗?如果你忽略它,是否满足组合定律?
虽然您提出的 Functor
实例定义确实无法编译,但并不是因为您所说的原因。而且它也是“本质上”正确的,只是没有以满足编译器的方式编写。
为方便起见,这里再次给出您的定义:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
这是您在尝试编译时遇到的实际错误:
Could not match type
a02
with type
b1
while trying to match type Either a0 a02
with type Either a0 b1
while checking that expression a
has type Either a0 b1
in value declaration functorEither
where a0 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
b1 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
a02 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
我承认这有点难以解释,如果你没有预料到的话。但这与 Either a
的 map
需要类型 forall b c. (b -> c) -> Either a b -> Either a c
这一事实有关。所以 map _ a = a
左边的 a
类型是 Either a b
,而右边的类型是 Either a c
- 这些是不同的类型(通常),因为 b
和 c
可以是任何东西,所以你不能使用相同的变量 a
来表示每种类型的值。
(This 问题,虽然是关于 Haskell 而不是 Purescript,但更深入地解释了这个错误。)
要修复它,正如上面问题中所暗示的那样,您必须明确提及您要映射的值是 Left
值:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ (Left a) = Left a
这很好,因为 Left a
可以在左侧解释为 Either a b
类型,在右侧解释为 Either a c
.
至于实例“做什么”:“a b 不是仿函数,只有 eith a 是仿函数”是正确的 - 因为仿函数必须采用一种类型变量,Either a
会,但 Either a b
不会。是的,因为在 Either a b
和 Either a c
之间实际“变化”的类型变量是在 Right
中使用的类型变量,map
必须只映射到 Right
值,并单独保留 Left
个 - 这是唯一能满足所需类型的东西。
Either a b
通常被解释为表示计算结果,其中 Left
值表示失败,而 Right
值表示成功。从这个意义上说,它是 Maybe
的一个稍微“扩展”的版本——不同之处在于,失败不是由单个值 (Nothing
) 表示,而是得到一段数据 (a
输入 Either a b
) 它可以告诉您有关错误的信息。但是 Functor
实例与 Maybe
实例的工作方式相同:它映射任何成功,并单独留下失败。
(但是没有合乎逻辑的理由说明您 不能 “映射”Left
值。Bifunctor class 是 Functor
的扩展,它可以做到这一点。)
查看 Either 是如何定义为函子的,我可以看到
derive instance functorEither :: Functor (Either a)
这对我来说是“你可以 map
一个 Either 只要你可以 map
它的元素。
但两者都不只有一个元素。如果没有 derive
,这将如何实现?这是我尝试过的:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
当然,类型在这里不起作用:
右边有这个签名:map :: forall a b. (a -> b) -> f a -> f b
然而,左派不行:map :: forall a b. (a -> b) -> f a -> f a
我的部分直觉是 Either a b
不是函子,只有 Either a
是函子。这就是为什么 map
对 Right
有效并忽略 Left
这并没有真正让我对它的实现方式有任何直觉。我仍然需要一种匹配两个构造函数的方法,不是吗?
另一方面,我认为用 identity
替换内部函数的 map
的实现在技术上对仿函数来说是守法的吗?如果你忽略它,是否满足组合定律?
虽然您提出的 Functor
实例定义确实无法编译,但并不是因为您所说的原因。而且它也是“本质上”正确的,只是没有以满足编译器的方式编写。
为方便起见,这里再次给出您的定义:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ a = a
这是您在尝试编译时遇到的实际错误:
Could not match type
a02
with type
b1
while trying to match type Either a0 a02
with type Either a0 b1
while checking that expression a
has type Either a0 b1
in value declaration functorEither
where a0 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
b1 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
a02 is a rigid type variable
bound at (line 0, column 0 - line 0, column 0)
我承认这有点难以解释,如果你没有预料到的话。但这与 Either a
的 map
需要类型 forall b c. (b -> c) -> Either a b -> Either a c
这一事实有关。所以 map _ a = a
左边的 a
类型是 Either a b
,而右边的类型是 Either a c
- 这些是不同的类型(通常),因为 b
和 c
可以是任何东西,所以你不能使用相同的变量 a
来表示每种类型的值。
(This 问题,虽然是关于 Haskell 而不是 Purescript,但更深入地解释了这个错误。)
要修复它,正如上面问题中所暗示的那样,您必须明确提及您要映射的值是 Left
值:
data Either a b = Left a | Right b
instance functorEither :: Functor (Either a)
where
map f (Right b) = Right $ f b
map _ (Left a) = Left a
这很好,因为 Left a
可以在左侧解释为 Either a b
类型,在右侧解释为 Either a c
.
至于实例“做什么”:“a b 不是仿函数,只有 eith a 是仿函数”是正确的 - 因为仿函数必须采用一种类型变量,Either a
会,但 Either a b
不会。是的,因为在 Either a b
和 Either a c
之间实际“变化”的类型变量是在 Right
中使用的类型变量,map
必须只映射到 Right
值,并单独保留 Left
个 - 这是唯一能满足所需类型的东西。
Either a b
通常被解释为表示计算结果,其中 Left
值表示失败,而 Right
值表示成功。从这个意义上说,它是 Maybe
的一个稍微“扩展”的版本——不同之处在于,失败不是由单个值 (Nothing
) 表示,而是得到一段数据 (a
输入 Either a b
) 它可以告诉您有关错误的信息。但是 Functor
实例与 Maybe
实例的工作方式相同:它映射任何成功,并单独留下失败。
(但是没有合乎逻辑的理由说明您 不能 “映射”Left
值。Bifunctor class 是 Functor
的扩展,它可以做到这一点。)