对于一些对monad一无所知的人来解释monad类型类的最佳monadic类型是什么?我应该使用标准Haskell库中的某些东西,还是应该构建一些新类型的东西?
答案 0 :(得分:3)
我认为激励monad的最佳方法是显示有多少嵌入式域特定语言具有monad的结构:
.then
作为绑定操作?.
运营商使用monads,您可以将6502的汇编程序嵌入到程序link或甚至BASIC代码link
中monad模式允许您从代码集中精力计算重要的计算细节,从而消除不必要的复杂性。
当您想要创建自己的EDSL时,了解monad模式将很有用。
答案 1 :(得分:1)
Maybe
monad(在我看来)是最容易理解的。一旦你通过了(简单)代数类型的概念,理解Maybe
monad的工作原理是相当简单的。
如果有人在理解Maybe
的构造函数时遇到问题,你可以给它们写一个基本相同的类:
class Maybe(object):
def __init__(self, value=None):
self.__just = value
def just(self):
if self.isJust():
return self.__just
else:
raise ValueError('None')
def isJust(self):
return self.__just is not None
def fmap(self, f):
if self.isJust():
return Maybe(f(self.just()))
else:
return Maybe()
def bind(self, fM):
"""fM must return a value of type Maybe"""
if self.isJust():
return fM(self.just())
else:
return Maybe()
def __repr__(self):
if self.isJust():
return 'Just ({})'.format(self.just())
else:
return 'Nothing'
def head(some_list):
if len(some_list) == 0:
return Maybe()
else:
return Maybe(some_list[0])
def idx(some_list, i):
if idx < len(some_list):
return Maybe(some_list[i])
else:
return Maybe()
print head([1, 2, 3]).bind(
lambda x: Maybe(2 * x)).bind(
lambda x: Maybe(x + 1)).bind(
lambda x: Maybe(x + 3))
print head([[1, 2, 3]]).bind(
lambda xs: idx(xs, 0)).bind(
head).bind(
lambda x: 2 * x)
print head([[1, 2, 3]]).bind(
lambda xs: idx(xs, 1)).bind(
head).bind(
lambda x: 2 * x)
此代码将打印出来
Just (6)
Nothing
Nothing
这与Haskell中的Maybe
monad具有相同的功能(或多或少),只是在Python中使用类重新实现。 Haskell中的return
函数被构造函数替换,>>=
被.bind
替换。
答案 2 :(得分:1)
我认为让monadic模式从实际使用中产生是很重要的。选择一些类型并引导某人解决由一元模式自然表达的问题可能具有启发性。
在我的头脑中,很容易争论Maybe
的好处,有人担心明显会导致嵌套错误处理,然后谈谈如何
case f x of
Nothing -> Nothing
Just y -> case g y of
Nothing -> Nothing
Just z -> case h z of
Nothing -> Nothing
Just q -> case r q of
Nothing -> Nothing
Just end -> end
实际上是一个非常非常常见的模式,Haskell可以让你抽象出来。
然后讨论配置以及如何将Config
数据类型传递给许多函数以使它们运行是有用的。最终编写像
go config in =
let (x, y) = f config $ g config $ h config in
in finally config x (we'reDone config y)
但这又是Haskell中一个非常常见的模式,它很烦人,但有一个减轻冗长的共同策略。
最后,将状态变异称为像
这样的链接内同态let state4 = (modify4 . modify3 . modify2 . modify1 :: State -> State) state0
以及如何提高你的“修改链”,同时也不会让你从中间步骤中获取任何信息(至少不会将它与你的状态一起穿过)。< / p>
同样,这可以通过具有奇怪名称的通用抽象模式在Haskell中非常均匀地解决。你听说过Monads的故事,对吧?
答案 3 :(得分:0)
我所拥有的一个更深刻的见解是,monad可以被视为命令式编程语言,你可以编写。所以也许你应该用它们构建一种“语言”,这样他们就能掌握抽象的强大程度。
我认为为他们创建编程语言将是一个很好的视角。
例如,首先添加状态
import Data.Map as M
import Control.Monad
import Control.Monad.State
data Variable = IntV Int | StringV String ..
type Context = M.Map String Variable
type Program a = State Context a
然后添加日志记录:
类型程序a = WriterT [String](状态上下文)a log x = tell [x]
然后添加例外:
键入Program a = WriterT [String](StateT Context Either)a
然后你添加延续等。
通过这种方式,您可以向他们展示您可以使用monad来构建一个对您的问题非常有用的环境。在此之后,如果他们感兴趣,你会向他们展示monad的解剖结构以及它们是如何构建的。
例如,首先展示Maybe monad。首先给它们纯粹的lambda版本:
data Perhaps a = Sure a | Nope
next (Sure a) f = f a
next (Nope) f = Nope
向他们展示如何使用lambda进行计算:
small x | x < 100 = Sure x
| otherwise = Nope
between x y z | x < z < y = Sure z
| otherwise = Nope
small 10 `next` (\b -> between 5 20 b)
然后向他们展示如何将其转换为符号:
small x `next` (\b -> between 5 20 b
`next` (\c -> between 10 14 c))
建议如果我们这样写它会很方便:
small x -> \b ->
between 5 20 b -> \c ->
between 10 14 c
然后介绍做符号:
b <- small x
c <- between 5 20 b
between 10 14 c
现在他们已经从那里发明了你的符号,你可以解释一些其他的monad。