寻找学习练习:实施这些单子

时间:2009-10-03 16:05:40

标签: functional-programming monads

在了解新的编程主题时,我通常会遵循一种模式:我阅读它,我理解它,然后我编写了一些示例来确保我真的得到它

我已经阅读了很多关于monad的内容,我相信我理解并得到它们。我现在正处于一个阶段,我真的想编写一些monad来巩固我的理解,并真正弄清楚如何为各种类型实现 bind

问题在于我无法想到许多明显的monad要实现,所以我正在寻找建议。最好是,我想要一个推荐列表,一些简单的,一些不那么容易。

我也意识到虽然monad用于在功能程序中“封装”副作用,但它们也比这更通用。因此,我希望建议包括既包含副作用又包含一些常规效果的monad。

谢谢!

(作为旁注:我将使用f#来做到这一点,但我认为这个问题可以适用于任何函数式语言)。

3 个答案:

答案 0 :(得分:5)

我认为All About Monads中的目录是一个好的开始(延续monad实际上对于catamorphisms有用,参见例如here);另外parsers,可能还有transactional effectsAsync是另一个很好的尝试自己实现的(逻辑上单线程的代码,它跨越不同的实际线程是非阻塞的)。 Reactive Framework的基础monad看起来像是一个很好的高级挑战。

答案 1 :(得分:2)

遵循某种一元法的数据结构/计算列表非常丰富。

它从列表中通过可选数据(F#中的'a option),延续和多线程到达解析器等高度复杂的事物。

刚开始实施其中一些。 基本训练:

// Identity monad

let something = ident {
    let! value = id 42
    return value
}

let somethingelse = ident {
    let! value = something
    let! otherValues = id 40
    return value + othervalue
}


// Implement maybe for 'a option
let sum = maybe {
    let! a = maybeInputNumber("a")
    let! b = maybeInputNumber("b")
    let! c = maybeInputNumber("c")
    return a + b + c
}

match sum with
| None -> ...
| Some(n) -> ...

您还可以通过使用辅助函数和显式monadic语法来增加理解力。

// Given m >>= f for m.Bind(f)

let (>-) f monad = monad >>= (fun k -> return(f x))

// What's this?
let res = ((+) 1) >- [1..10]

如果您需要一些复杂的示例,请查看monadic parser combinators。这将允许您在普通F#中实现复杂的递归下降解析器(看看FParsec - 项目)

let parseVector = parser {
    do! ignore $ char '('
    let! [x;y;z] = sepBy parseNumber "," 
    do! ignore $ char ')'
    return new Vector(x, y, z)
}

对此的简单实现基于以下类型:

type 't Computation = 
    | Error of ...
    | Result of 't

type Input     = char list
type 'a Parser = Input -> (('a * Input) Computation)

尝试实施 bind return ; - )

作为一般提示:如果你真的想要了解自然环境中的monad,你将不得不使用Haskell ;-)在F#中只有计算表达式,只是模糊的模拟,但Haskell引入了通用接口任何monadic计算。完美尝试它们!

答案 2 :(得分:1)

虽然我认为Haskell是学习monad的自然语言并不具有挑战性,但我发现一个非常有用的练习是将monadic计算带到一个开箱即用的Haskell语言中。为他们提供超级顺畅的支持。它完全可以用任何语言,任何合理的高级语言,它可能是有创意的,实际上让它们看起来很好 - 在这个过程中学到了很多东西!我已经看过Python的酷monadic语法(我认为在Valued Lessons)。

还有Clojure的clojure.contrib.monads库,它为在Lisp中使用monad提供了很好的设施。尝试在功能上重新创建它可能非常有启发性。此外,有时使用它来代替Haskell可能有助于从Haskell的语法细节中分离出一般模式(尽管它们相当很好,但可以肯定)。