【发布时间】:2023-03-18 02:54:01
【问题描述】:
我想在 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))
正如现在实现的那样,return 和 >>= 属于命名空间Main,我必须将它们与Prelude.return 和Prelude.>>= 区分开来。如果我想让 Haskell 像对待任何其他类型的 monad 一样对待 M,并正确地重载 Prelude 中的 monad 运算符,我该怎么做?
【问题讨论】:
-
类型类在在线书籍learnYouAHaskell中有很好的解释。链接部分涉及制作 monad。
标签: haskell operator-overloading monads