在了解新的编程主题时,我通常会遵循一种模式:我阅读它,我理解它,然后我编写了一些示例来确保我真的得到它。
我已经阅读了很多关于monad的内容,我相信我理解并得到它们。我现在正处于一个阶段,我真的想编写一些monad来巩固我的理解,并真正弄清楚如何为各种类型实现 bind 。
问题在于我无法想到许多明显的monad要实现,所以我正在寻找建议。最好是,我想要一个推荐列表,一些简单的,一些不那么容易。
我也意识到虽然monad用于在功能程序中“封装”副作用,但它们也比这更通用。因此,我希望建议包括既包含副作用又包含一些常规效果的monad。
谢谢!
(作为旁注:我将使用f#来做到这一点,但我认为这个问题可以适用于任何函数式语言)。
答案 0 :(得分:5)
我认为All About Monads中的目录是一个好的开始(延续monad实际上对于catamorphisms有用,参见例如here);另外parsers,可能还有transactional effects。 Async是另一个很好的尝试自己实现的(逻辑上单线程的代码,它跨越不同的实际线程是非阻塞的)。 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的语法细节中分离出一般模式(尽管它们相当很好,但可以肯定)。