2014-01-13 84 views
0

为了更好地理解monad,我试图写我自己的。我从一些非一元代码开始,可以使用一些帮助将它翻译成单元。Haskell:翻译为Monad

这个人为的例子的基本思想:对于计算的每个整数结果,我想跟踪该整数是偶数还是奇数。例如,在4 + 5 = 9中,我们可能会返回(9, Odd)。我想用>>=连锁/组合计算。例如:

return 1 >>= (+2) >>= (+5) >>= (+7) =result=> (15, Odd) 

现在,我有以下的非单一产品代码:

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) 

有什么办法我能翻译上面的代码放到一个单子?我应该寻找哪些模式以及它们的常用翻译模式是什么?

非常感谢提前!

+2

这不容易承认一元翻译。 Monads通过类型进行参数化,对任何类型都有意义。 Yor计算只对内部人员有意义。 –

+1

看起来你正在试图模拟状态转换/动作,在这种情况下,你的状态就是“质量”。你会想看看[** State Monad **](http://learnyouahaskell.com/for-a-few-monads-more),其中你的状态monad是由“Quality”和你的操作参数化的, (+1)'会变成状态行为。 – aaronlevin

+0

@ n.m。好点,也是我开始看到和想知道的。什么可能是一个简单的,通用的过程的更好的例子,适合这样的练习? –

回答

0

很多从这个学习的。非常感谢评论员和你的时间和指导的答案!

总结:

解决方案:作为@牛米。和其他人评论说,这个例子没有很好的monad翻译,因为我的原始模型不是类型通用的。 Monads最适合类型通用计算模式。给出的好例子包括用于计算失败的Maybe monad和用于通过计算链存储和携带附件状态信息的State monad。

作为备用解决方案,@GabrielGonzalez提供了一个使用类型实例化的出色解决方案。这保持了我原始模型的固有类型特异性,但扩大了它的界面以支持更多类型的类接口并清理功能性交互。

下一个步骤:由于@weirdcanada和别人推荐的,我想我会去与State单子玩,看我怎么可以把它应用到这个特殊的例子。然后,我可以试着用自己定义的Maybe作为@ n.m。推荐的。

再次,非常感谢那些评论和回应!

3

我想你真正想要的是一个Qualified例如Num

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号:

>>> let a = fromInteger 3 :: Qualified 
>>> let b = fromInteger 4 :: Qualified 
>>> a 
Qualified {isEven = False, value = 3} 
>>> b 
Qualified {isEven = True, value = 4} 
>>> a + b 
Qualified {isEven = False, value = 7} 
>>> a * b 
Qualified {isEven = True, value = 12} 
+1

OP可能想要一个'Num'实例,但我认为更广泛的目标是OP想要学习和理解monads。 – aaronlevin

+3

我担心,在这个特定问题的背景下教授monad会造成更多的伤害而不是好处。 –

+0

@GabrielGonzalez很好的关注,并担心承认。什么可能是一个更好的简单类型的monad,可以从头开始编写,以获得更好的单子感? –