[英]Satisfying monad laws without a type constructor
给定例如类型
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
是单子吗?
Tree a
是不是一个单子,一般地或对于任何特定的a
, Tree
本身就是一个单子。 monad不是一种类型,它是任何类型与该类型的“ monadic版本”之间的对应关系。 例如, Integer
是Integer
的类型, Maybe Integer
是Maybe
monad中的整数的类型。
因此,作为类型的StringTree
不能为monad。 只是不一样的事情。 您可以尝试将其想象为monad中字符串的类型,但是您的函数stringTreeReturn
等等与它们的monadic通信者的类型不匹配。 查看Maybe
monad中>>=
的类型:
Maybe a -> (a -> Maybe b) -> Maybe b
第二个参数是Maybe
monad( Maybe b
)中从a
到任意类型的函数。 stringTreeBind
具有类型:
String -> (String -> StringTree) -> StringTree
第二个参数只能是从一个函数String
到的一元版本String
,而不是为了任何类型的一元版本。
因此,您无法对StringTree
值的任意monadic类型的值做任何事情,这就是为什么不能将其作为实例的原因。 即使您能以某种方式将其视为monad,当通用monadic代码期望能够以对StringTree
没有意义的方式使用通用monadic操作时,事情也会开始出错。
最终,如果您认为它“像” monad是因为它是容器中的String
,其行为可以类似于monadic容器,那么最简单的事情就是简单地使其成为任何类型的通用容器( Tree a
)。 如果您需要辅助功能,具体取决于它是一棵字符串树,则可以将该代码编写为仅对Tree String
值进行操作,并且它将与通常在Tree a
上工作的代码一起愉快地共存。
不。您正在查看类型和种类之间的区别。 简单地说,一种是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
接受一个参数。
这是表达和解开问题的很长的路要走,但是希望它可以显示类型和种类之间的区别。
不,那不是单子。 想一想,您可以写一个monad m
以便只有m String
可能吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.