流(惰性列表)和单子之间是否存在任何区别?从概念和数学的角度来看,而不是从技术实现的角度来看。
或者,是否存在双唯一的、一一对应的关系?
更准确地说,作为流,它意味着来自Scheme 语言的SRFI-41的“偶数流” 。
它是单子以外的另一个类别吗?如果是这样,它是什么类别?
“偶数流”可以保证对副作用的控制,比如单子吗?
流(惰性列表)和单子之间是否存在任何区别?从概念和数学的角度来看,而不是从技术实现的角度来看。
或者,是否存在双唯一的、一一对应的关系?
更准确地说,作为流,它意味着来自Scheme 语言的SRFI-41的“偶数流” 。
它是单子以外的另一个类别吗?如果是这样,它是什么类别?
“偶数流”可以保证对副作用的控制,比如单子吗?
正如 Salil 已经说过的,这两者是不同的概念:
流是(可能是无限的)值列表,通常但不一定以惰性方式计算,即仅在请求时存储某种计算值的方式。周围有很多不涉及单子的例子:
(define integers (cons-stream 1 (stream-map (lambda (x) (+ x 1)) integers))
将有限的、预先计算的列表视为流也非常有用,因为您可以在任何可以使用(可能或必然)有限惰性流的地方使用它们。
因此,流是具有next: streamType -> (valueType streamType)
获取下一个值和剩余流的操作的东西。
另一方面, Monad 与其说是一种数据结构,不如说是一种通过组合单个命令来编写源代码的方式。
可能最简单有用的例子是“Maybe monad”——我不确定它在 Scheme 中会是什么样子,对不起,但想法是:给定一个计算列表(f g h)
和一个输入x
,按顺序执行计算,几乎就像如果给定(f (g (h x)))
,但让每个函数优雅地失败:如果g
返回nil
,不要调用(f nil)
,而是nil
立即返回。
当然,您可以以各种有用的方式将两者结合起来,并使用 monad 计算您的流值,或者封装像 I/O 流这样的流的使用,这些流并不完全符合 monad 中函数式编程的期望(以避免代码存储引用流的某些先前状态),但它们的用途完全不同。想想抽象层(关闭封面,不要看内部):一个单子,应用于函数,给你一个函数。另一方面,流不是更高的函数,而是值列表。
显然,由 monad 定义(或返回,取决于您的观点)的函数可以是流的实现,而且从流中提取的值也可以是 monad。但正如你在上面看到的,有一些 monad 实现了与流完全不同的东西。是否存在未作为 monad 实现的流可能取决于您使用该术语的确切含义。我必须承认,目前我不确定无限流是否适合单子;有限列表显然可以。