在阅读它们之前,我尝试实现一个 monad,我只是对 Monad 的概念有一种“感觉”。
我读到关于 Monad 的所有内容,Just 和 Nothing 是函数,而不是 Monad 的类型,但我认为每个 Maybe monad 当它绑定到另一个时最终会崩溃成 Just 或 Nothing monad(或者这就是我写的)值。
我的理解有误吗?另外,在这种情况下,我通过绑定使 Monad 返回自身,但也许我应该只返回未包装的值,并且该绑定已经是一个 comp。
这是我写的:
from abc import ABCMeta
class Monad(metaclass = ABCMeta):
def __init__(self, value = None) -> None:
self._unit = value
@property
def unit(self):
return self._unit
@unit.setter
def unit(self, value):
self._unit = value
def __repr__(self) -> str:
return f'{self.__class__.__name__} ( {self._unit} )'
class Maybe(Monad):
def bind(self, function):
self.unit = function(self._unit) if self.unit is not None else None
self.__class__ = Nothing if self.unit is None else Just
return self
class Nothing(Maybe):
pass
class Just(Maybe):
pass
a = Maybe(1)
b = Maybe(1)
b.bind(lambda x: x + 1).bind(lambda x: x + 1).bind(lambda x: x + 1).bind(lambda x: x + 1)
c = Maybe()
c.bind(lambda x: x + 1).bind(lambda x: x + 1).bind(lambda x: x + 1)
print(a, a.unit)
print(b, b.unit)
print(c, c.unit)
我仍然认为这很丑陋,我需要让它变得更好......但我只是想了解我的概念是否正确
你无法将 Monad 完全翻译为动态语言,甚至无法用大多数静态类型语言来表达它们(你需要像 HKT 这样的东西,很少有语言支持)。在这种特殊情况下,您还需要标记联合。
Just 和 Nothing 都是函数
不,他们不是。它们是“类型构造函数”,并且(据我所知)Python 中没有类似的东西(即使有内置的类型提示)。类型构造函数与函数类似,但函数对值进行操作:您可以获取值、返回值等。类型构造函数对类型进行操作:您可以将类型作为参数,然后返回一个新类型。 因此
Maybe
类型是类型的标记联合:
Maybe some_type
是 Just some_type
或 Nothing
。注意:该类型是 Just some_type
、不是
Just
或 some_type
。如果愿意的话,静态类型编译语言有两个“级别”:编译时存在的type级别和运行时存在的term或value级别。像 Python 这样的动态解释语言只有第二级,而 Haskell 中的 Monad 存在于第一级,这就是为什么从这个角度理解它们如此困难的部分原因。 那么 Monad 到底是什么?我要抄袭埃里克·利珀特 (Eric Lippert) 的精彩解释:
有一个“单元”操作(有时被称为“返回”操作,令人困惑),它从普通类型中获取值并创建等效的一元值。本质上,这提供了一种获取未放大类型的值并将其转换为放大类型的值的方法。它可以作为 OO 语言中的构造函数来实现。
有一个“绑定”操作,它接受一个单子值和一个可以转换该值的函数,并返回一个新的单子值。 Bind 是定义 monad 语义的关键操作。它让我们可以将对未放大类型的操作转换为对放大类型的操作,这遵循前面提到的函数组合规则。
因此将所有这些翻译成 Python 将会很困难。如果您曾经使用任何静态类型编译语言进行过编程,即使该语言的类型系统不够强大,无法真正表达 Monad(例如 Java、C#、Typescript),您也会在这方面获得更多经验