Haskell 中的所有 Monad 实例是否只是从 Hask 映射到 Hask 的不同方式?
Are all Monad instances in Haskell just different ways for mapping from Hask to Hask?
我正在阅读 Haskell/Category theory and here is the definition of monad 那篇文章:
A monad is a special type of functor, from a category to that same
category, that supports some additional structure. So, down to
definitions. A monad is a functor M:C->C, along with two
morphisms for every object X in C:
unit: X -> M(X)
join: M(M(X)) -> M(X)
据我了解,在Haskell中return
相当于unit
。但是 return
我可以写:
x :: [Int] -- x is a member of Lst category
x = return 5
这是 Haskell 中的有效代码。
现在,如您所见,这里的 5
不是 Lst
的成员,但 return
为它工作。
所以,我猜 Lst
不是来自 M:C->C 的 С。但是那是谁呢?
也许正确答案是 Hask
,但我不确定“functor from a category to its subcategory”与“[=32] 是否相同=]从一个类别到同一类别的函子".
根据定义,单子是一个内函子。类型类 Functor
实际上代表了内函数,因为 Functor
的实例是为类型构造函数定义的,这些构造函数是 type-level 接受一个类型的函数和 return 一个新类型(即, 他们有种类 * -> *
).
return :: Monad m => a -> m a
,所以return
可以取Int
类型的值,return可以取[Int]
类型的值也就不足为奇了。
这是一个常见的混淆点,你问的问题足够清楚,可以回答。
I'm not sure that "functor from category to it's subcategory" is the same as "functor from category to the same category".
不一样。一个函子由四部分数据组成:源类别C,目标类别D,C的对象到D的对象的映射,C的态射到D的态射的映射,满足一些条件。如果你改变了 D,那么你就改变了函子。
然而,当我们定义一个函子时,我们通常在类别 D 中有一些选择。我从你的问题中推断出 Lst
是 Hask
的子类别,其对象的类型为 [a]
,虽然我不确定 Lst
的态射应该是什么。我们可以定义以下两种形状之一的函子 []
:
[]
: Hask
-> Lst
(即[]
的目标类别是Lst
)
[]
: Hask
-> Hask
(即[]
的目标类别是Hask
)
这些是技术上不同的函子,我们必须做出选择。在这种情况下,正确的选择是选择 2。我们需要源类别和目标类别相同,因为我们需要在 join
中将 []
应用于 []
的输出。所以 C = Hask
和 M = []
.
一般来说,考虑像 Lst
这样被定义为某种类型构造函数的图像的类别很少有用。我不确定这个(非常普遍的)想法从何而来。我建议你搁置 "the category Lst
" 的想法。现在只要一个类别就够了!
打个比方,考虑对实数求平方的函数 f(x) = x^2。我们可以将其视为函数 f : R -> R 从实数到实数,即使 f(x) 恰好只取非负实数。 f 的目标不必等于 f 的映像(f 在其输入值上实际获得的值)。
我正在阅读 Haskell/Category theory and here is the definition of monad 那篇文章:
A monad is a special type of functor, from a category to that same category, that supports some additional structure. So, down to definitions. A monad is a functor M:C->C, along with two morphisms for every object X in C:
unit: X -> M(X)
join: M(M(X)) -> M(X)
据我了解,在Haskell中return
相当于unit
。但是 return
我可以写:
x :: [Int] -- x is a member of Lst category
x = return 5
这是 Haskell 中的有效代码。
现在,如您所见,这里的 5
不是 Lst
的成员,但 return
为它工作。
所以,我猜 Lst
不是来自 M:C->C 的 С。但是那是谁呢?
也许正确答案是 Hask
,但我不确定“functor from a category to its subcategory”与“[=32] 是否相同=]从一个类别到同一类别的函子".
根据定义,单子是一个内函子。类型类 Functor
实际上代表了内函数,因为 Functor
的实例是为类型构造函数定义的,这些构造函数是 type-level 接受一个类型的函数和 return 一个新类型(即, 他们有种类 * -> *
).
return :: Monad m => a -> m a
,所以return
可以取Int
类型的值,return可以取[Int]
类型的值也就不足为奇了。
这是一个常见的混淆点,你问的问题足够清楚,可以回答。
I'm not sure that "functor from category to it's subcategory" is the same as "functor from category to the same category".
不一样。一个函子由四部分数据组成:源类别C,目标类别D,C的对象到D的对象的映射,C的态射到D的态射的映射,满足一些条件。如果你改变了 D,那么你就改变了函子。
然而,当我们定义一个函子时,我们通常在类别 D 中有一些选择。我从你的问题中推断出 Lst
是 Hask
的子类别,其对象的类型为 [a]
,虽然我不确定 Lst
的态射应该是什么。我们可以定义以下两种形状之一的函子 []
:
[]
:Hask
->Lst
(即[]
的目标类别是Lst
)[]
:Hask
->Hask
(即[]
的目标类别是Hask
)
这些是技术上不同的函子,我们必须做出选择。在这种情况下,正确的选择是选择 2。我们需要源类别和目标类别相同,因为我们需要在 join
中将 []
应用于 []
的输出。所以 C = Hask
和 M = []
.
一般来说,考虑像 Lst
这样被定义为某种类型构造函数的图像的类别很少有用。我不确定这个(非常普遍的)想法从何而来。我建议你搁置 "the category Lst
" 的想法。现在只要一个类别就够了!
打个比方,考虑对实数求平方的函数 f(x) = x^2。我们可以将其视为函数 f : R -> R 从实数到实数,即使 f(x) 恰好只取非负实数。 f 的目标不必等于 f 的映像(f 在其输入值上实际获得的值)。