4

给定例如一个类型

data Tree a = Branch (Tree a) (Tree a)
            | Leaf a

我可以轻松地为 Functor、Applicative、Monad 等编写实例。

但是如果“包含”类型是预先确定的,例如

data StringTree = Branch StringTree StringTree
                | Leaf String

我失去了编写这些实例的能力。

如果我要为我的 StringTree 类型编写函数

stringTreeReturn :: String -> StringTree
stringTreeBind   :: String -> (String -> StringTree) -> StringTree
stringTreeFail   :: String -> StringTree
-- etc.

满足单子定律,我还能说那StringTree是单子吗?

4

3 回答 3

3

Tree a不是一个 monad,无论是一般的还是任何特定的aTree 它本身都是一个 monad。monad 不是类型,它是任何类型与该类型的“monadic 版本”之间的对应关系。例如,Integer是整数Maybe Integer的类型, 是Maybemonad 中的整数类型。

因此,StringTree作为类型的 不能是单子。它只是不一样的东西。您可以尝试将其想象为 monad 中的字符串类型,但您的函数stringTreeReturn等与它们的 monadic 对应对象的类型不匹配。查看monad>>=中的类型:Maybe

Maybe a -> (a -> Maybe b) -> Maybe b

第二个参数是monad ( )中从 somea任何类型的函数。具有以下类型:MaybeMaybe bstringTreeBind

String -> (String -> StringTree) -> StringTree

第二个参数只能是从String到 的单子版本的函数String,而不是到任何类型的单子版本的函数。

因此,您不能对任意一元类型的StringTree值做所有可以做的事情,这就是为什么不能将其作为实例的原因。即使您可以以某种方式将其视为 monad,但当通用 monadic 代码期望能够以对StringTree.

归根结底,如果你认为它“像”一个 monad,因为它String位于一个行为类似于 monad 容器的容器中,那么最简单的做法就是让它成为任何类型的通用容器 ( Tree a)。如果您需要具有专门依赖于它作为字符串树的辅助功能,那么您可以将该代码编写为仅对Tree String值进行操作,并且它将很高兴地与通常在Tree a.

于 2012-08-23T01:17:51.503 回答
2

不,您正在查看typekind之间的区别。简单地说,a kind 是 Haskell 对类型进行分类的方式,因此它是类型之上的抽象级别。ghci可以帮忙。

:type stringReturn
stringReturn :: String -> StringTree
:type Functor
<interactive>:1:1: Not in scope: data constructor `Functor'

所以马上,我们可以看到一个函数,它有一个类型,与一个类型完全不同,它有一个种类。

我们也可以询问ghci种类。

:kind Functor
Functor (* -> *) -> Constraint
:kind StringTree
StringTree :: *
:kind Tree
Tree :: * -> *

种类*在其符号中用于变量。我们可以从上面的交互中看到,Functor期望通过一个参数参数化的类型。我们还可以看到,StringTree它不带任何参数,并且Tree只带一个。

这是表达和解开您的问题的漫长方式,但希望它能够显示类型和种类之间的区别。

于 2012-08-22T13:16:36.277 回答
0

不,那不会是一个单子。想一想,你能写一个m只有m String可能的单子吗?

于 2012-08-22T13:05:07.520 回答