繁体   English   中英

在没有类型构造函数的情况下满足单子法则

[英]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是不是一个单子,一般地或对于任何特定的aTree 本身就是一个单子。 monad不是一种类型,它是任何类型与该类型的“ monadic版本”之间的对应关系。 例如, IntegerInteger的类型, Maybe IntegerMaybe 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM