例如类似
的类型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.
满足monad法则,我还能说StringTree
是monad吗?
答案 0 :(得分:3)
Tree a
不是一个monad,无论是一般的还是任何特定的a
,Tree
本身是monad。 monad不是一个类型,它是任何类型和类型的“monadic版本”之间的对应关系。例如,Integer
是整数的类型,Maybe Integer
是Maybe
monad中的整数类型。
因此,StringTree
是一种类型,不能是monad。这不是一回事。您可以尝试将其想象为monad中的字符串类型,但是您的函数stringTreeReturn
等与其monadic通讯员的类型不匹配。查看>>=
monad中Maybe
的类型:
Maybe a -> (a -> Maybe b) -> Maybe b
第二个参数是a
monad(Maybe
)中某些Maybe b
到任何类型的函数。 stringTreeBind
的类型为:
String -> (String -> StringTree) -> StringTree
第二个参数只能是从String
到String
的monadic版本的函数,而不是任何类型的monadic版本。
因此,您无法对任意monadic类型的值执行所有操作,而不能将其设置为StringTree
值,这就是为什么它不能成为实例的原因。即使你可以某种方式将它视为monad,当通用monadic代码期望能够以对StringTree
没有意义的方式使用泛型monadic操作时,事情就会出错。
最终,如果你认为它是“喜欢”monad,因为它在容器中的String
可以表现得与monadic容器类似,最简单的做法就是简单地将它作为任何容器的通用容器输入(Tree a
)。如果你需要具有特别依赖于它是字符串树的辅助功能,那么你可以将该代码编写为仅在Tree String
值上运行,并且它将与在{{上一般工作的代码一起快乐地共存。 1}}。
答案 1 :(得分:2)
没有。您正在查看类型和类之间的区别。简单地说,一种是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
只接受一个参数。
这是一个很长的方式来表达和解开你的问题,但希望它能显示出类型和种类之间的区别。
答案 2 :(得分:0)
不,那不是一个单子。想一想,你能写一个monad m
所以只有m String
是可能的吗?