在没有类型构造函数的情况下满足monad定律

时间:2012-08-22 12:37:27

标签: haskell monads functor category-theory

例如类似

的类型
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吗?

3 个答案:

答案 0 :(得分:3)

Tree a不是一个monad,无论是一般的还是任何特定的aTree 本身是monad。 monad不是一个类型,它是任何类型和类型的“monadic版本”之间的对应关系。例如,Integer是整数的类型,Maybe IntegerMaybe 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

第二个参数只能是从StringString的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是可能的吗?