为了更好地理解monad,我正在尝试自己编写。我从一些非monadic代码开始,可以使用一些帮助将其翻译成monad。
这个人为的例子的基本思路:对于计算的每个整数结果,我想跟踪该整数是偶数还是奇数。例如,在4 + 5 = 9
中,我们可能会返回(9, Odd)
。
我希望能够使用>>=
链接/撰写计算。例如:
return 1 >>= (+2) >>= (+5) >>= (+7) =result=> (15, Odd)
现在,我有以下非monadic代码:
data Quality = Odd | Even deriving Show
qual :: Integer -> Quality
qual x = case odd x of
True -> Odd
_ -> Even
type Qualifier = (Integer, Quality)
mkQ :: Integer -> Qualifier
mkQ x = (x, qual x)
plusQ :: Qualifier -> Qualifier -> Qualifier
plusQ (x, _) (y, _) = (x+y, qual (x+y))
chain = plusQ (mkQ 7) . plusQ (mkQ 5) . plusQ (mkQ 2)
有什么方法可以将上面的代码翻译成monad?我应该寻找哪些模式,以及它们的常见翻译模式是什么?
非常感谢提前!
答案 0 :(得分:3)
我认为您真正想要的是Num
的{{1}}个实例:
Qualified
这使您可以使用数学运算符直接操作data Qualified = Qualified { isEven :: Bool, value :: Integer }
instance Num Qualified where
(Qualified e1 n1) + (Qualified e2 n2) = Qualified e (n1 + n2)
where
e = (e1 && e2) || (not e1 && not e2)
(Qualified e1 n1) * (Qualified e2 n2) = Qualified (e1 || e2) (n1 * n2)
abs (Qualified e n) = Qualified e (abs n)
signum (Qualified e n) = Qualified e (signum n)
fromInteger n = Qualified (even n) n
数字:
Qualified
答案 1 :(得分:0)
从这一个中学到了很多东西。非常感谢您的时间和指导的评论员和答案!
总结:
解决方案:正如@n.m.和其他人评论说,这个例子没有一个好的monad翻译,因为我的原始模型不是类型泛型的。 Monad最适合类型通用计算模式。给出的好例子包括用于计算的Maybe
monad可能会失败,以及State
monad用于通过计算链存储和携带附件状态信息。
作为替代解决方案,@ GabrielGonzalez使用类型实例化提供了一个很好的解决方案。这保留了我原始模型的固有类型特异性,但扩展了它的界面以支持更多Num
类型类接口并清理功能交互。
后续步骤:正如@weirdcanada和其他人推荐的那样,我想我会和State
monad一起玩,看看如何将它应用到这个特定的例子中。然后我可以尝试一下自定义的Maybe as @ n.m。推荐使用。
再次,非常感谢那些评论和回应的人!