Dav*_*fau 4 monads haskell operator-overloading
我想在Haskell中创建自己的monad,让Haskell就像任何其他内置的monad一样对待它.例如,下面是用于创建monad的代码,该monad在每次调用时更新一些全局状态变量,以及使用它来计算quot函数调用次数的求值器:
-- define the monad type
type M a = State -> (a, State)
type State = Int
-- define the return and bind operators for this monad
return a x = (a, x)
(>>=) :: M a -> (a -> M b) -> M b
m >>= k = \x -> let (a,y) = m x in
let (b,z) = k a y in
(b,z)
-- define the tick monad, which increments the state by one
tick :: M ()
tick x = ((), x+1)
data Term = Con Int | Div Term Term
-- define the evaluator that computes the number of times 'quot' is called as a side effect
eval :: Term -> M Int
eval (Con a) = Main.return a
eval (Div t u) = eval t Main.>>= \a -> eval u Main.>>= \b -> (tick Main.>>= \()->Main.return(quot a b))
answer :: Term
answer = (Div (Div (Con 1972)(Con 2))(Con 23))
(result, state) = eval answer 0
main = putStrLn ((show result) ++ ", " ++ (show state))
Run Code Online (Sandbox Code Playgroud)
作为现在实施的,return并且>>=属于在命名空间Main,我必须从区分它们Prelude.return和Prelude.>>=.如果我希望Haskell M像任何其他类型的monad一样对待,并且正确地使monad运算符超载Prelude,我该怎么做?
Chr*_*kle 11
为了让你的新monad与所有现有的Haskell机制一起工作do- 例如 - 你需要做的就是将你的类型声明为类型类的一个实例Monad.然后,Prelude功能>>=,return等会跟你的新类型的工作,就像他们做的所有其他Monad类型.
但是,有一个限制,需要对您的示例进行一些更改.类型同义词(声明着type)不能成为类实例.(你M a的完全相同 Int -> (a, Int).)你需要使用data或newtype代替.(这两者之间的区别在这里是不相关的.)
这两个关键字都创建了一个真正的新类型; 特别是,他们创建了一个新的数据构造函数.您应该在任何基本的Haskell文本中阅读此内容.简单地说,newtype X a = Y (...)创建一个新的类型 X a ; 您可以使用构造函数创建该类型的值Y(它可以,并且通常与类型构造函数具有相同的名称X); 并且您可以通过模式匹配来消耗值Y.如果选择不导出数据构造函数Y,则只有模块中的函数才能直接操作值.
(有一个GHC的扩展TypeSynonymInstances,但它不会帮助你在这里,因为一个单独的问题:类型同义词不能部分应用;任何type X a = {- ... -}你可以只写X a或X Int或诸如此类的东西,从来都只是X你可以不写.instance Monad M因为M部分应用. )
在此之后,所有你需要做的是移动你的定义return,并>>=为instance Monad申报:
newtype M a = M (State -> (a, State))
instance Monad M where
return a = M $ \x -> (a, x)
m >>= k = {- ... -}
Run Code Online (Sandbox Code Playgroud)
请注意,实现(>>=)略有冗长,因为您需要newtype使用其数据构造函数来解包和重新包装M.查看in 的实现StateTtransformers,它使用记录访问器使其更容易.(您可以手动编写与许多其他软件包使用runM :: M -> State -> (a, State)的记录语法等效的函数transformers.)