STDOUT及其杂质


10

我已经阅读了很多有关函数式编程的书籍和文章,但仍然感到羞愧,因为无法确定地理解一些非常基本的概念。

函数式编程的主要思想之一是相同的输入始终应产生相同的输出。因此,按定义,查询数据库或写入文件无法以纯功能样式完成。例如,这就是我们需要monad的原因之一。

问题是-为什么我们认为STDOUT输出不纯?是的,任何文件处理程序都存在风险-我们永远无法确定总是会写入数据。但是STDOUT呢?为什么我们认为它不可靠?评估本身是否更加不可靠?我的意思是,我们总是可以拉动触发器,从而进行中断计算。

Answers:


6

因此,按定义,查询数据库或写入文件无法以纯功能样式完成。例如,这就是我们需要monad的原因之一。

没人“需要” monad,那只是描述事物的一种方式。实际上,这可能甚至不是最好的方法。某种形式的效果类型唯一性类型或基于完全线性逻辑的系统在理论上似乎更具说服力,但与众所周知的类型系统相比则更具根本性,表达起来也更复杂。Haskell中发现的Monadic IO是可用性和简单性之间的折衷,因为它实质上以一种易于与现有语言中已使用的ML样式类型系统共存的方式对完全命令式编程进行建模。

问题是-为什么我们认为STDOUT输出不纯?是的,任何文件处理程序都存在风险-我们永远无法确定总是会写入数据。但是STDOUT呢?为什么我们认为它不可靠?评估本身是否更加不可靠?我的意思是,我们总是可以拉动触发器,从而进行中断计算。

不是,我们也不是。整个程序的输入和输出可以简单地视为自变量,并且可以将整个程序视为一个大的纯函数。如果您从stdin中输入相同的内容,只要它向stdout输出相同的内容,它仍然是一个纯函数。实际上,在引入单例IO之前,Haskell使用基于流的I / O系统,该系统使用纯惰性流进行输入和输出。之所以删除它,是因为使用起来似乎很痛苦,这可能使您对为什么没有听说过这样的事情有所了解。:]

为了以一种愚蠢的方式提出观点,请考虑极简主义的深奥语言Lazy K

Lazy K是一种垃圾回收的,引用透明的功能性编程语言,具有一个简单的基于流的I / O系统。

Lazy K与其他此类语言的区别在于它几乎完全缺乏其他功能。例如,它不提供集成的Hindley-Milner多态类型系统。它没有附带支持平台无关的GUI编程以及与其他语言的绑定的扩展标准库。也不能编写任何此类库,因为除其他外,Lazy K不提供任何方法来定义或引用内置函数以外的任何函数。缺少对数字,字符串或任何其他数据类型的支持,弥补了这种能力的不足。不过,Lazy K是图灵完备的。

(...)

懒惰的K程序与数学函数生活在永恒的柏拉图领域中,Unlambda页面称其为“纯无类型lambda演算的有福领域”。就像垃圾回收对程序员隐藏了内存管理过程一样,引用透明性也隐藏了评估过程。为了查看Mandelbrot集的图片或为了“运行” Lazy K程序而需要进行一些计算的事实是实现细节。这就是函数式编程的本质。

(...)

如何处理无副作用的语言输入和输出?从某种意义上说,输入和输出不是副作用。可以说,它们是正面和反作用。在懒惰K中也是如此,在该程序中,程序被简单地视为从可能的输入空间到可能的输出空间的函数。

我怀疑您会找到比这更纯粹的功能语言!


但是请记住,以上内容仅适用于从本质上获取纯函数的输入和输出,并通过某种方式将它们“外部”连接到stdin / stdout。那和访问真实的系统级I / O原语之间有很大的区别。除非仔细封装,否则读写流的实施细节可能会泄漏杂质。

我希望这是您不能直接在Haskell中直接执行此操作的主要原因-明智的用例比使用Monadic IO苗条,对于后者而言,访问真实对象有很多好处。我认为,这就是为什么,例如,程序的命令行参数不会简单地作为参数传递给main,即使在直观上看起来应该如此。

不过,您可以在特定程序中恢复诸如此类的最低版本-只需将参数捕获为纯值,然后将该interact函数用于程序的其余部分即可。


主席先生,我必须承认,我对您的回答感到满意。您绝对应该写一本书Haskell,但我不是在开玩笑。
shabunc 2011年

@shabunc:我有时想知道我对SO的答案与已经达到一本书的大小有多接近……
CA McCann

您能举一个基于全线性逻辑的系统的例子吗?如果存在,那似乎很有趣。
配置器

@configurator:注意我如何链接到其他语言的特定语言,但是如何链接到线性逻辑的维基百科页面?las,如果我有一个例子,我会给出的。:[我所听到的只是CS研究的部分原型和实验系统。如果您想更深入地研究,这里有一些线性类型系统上相对容易理解的材料,可能会让您入门。
CA McCann

3

尽管功能程序的纯度是一个值得追求的目标,但实际上,由于您提到的原因,每个不重要的,有用的程序都会有一些杂质(或“副作用”)。

从定义上说,完全纯净的程序是一个密封的黑匣子,从本质上讲没有意思。

函数语言Haskell通过隔离副作用(例如monad中的输出)来解决此问题。monad保留了纯粹的函数式编程风格,同时仍然可以产生输出。


当然,你是对的。但我知道为什么100%的纯正是乌托邦。我的问题只是关于STDOUT。
shabunc 2011年

1
就像其他任何一样,STDOUT是一个副作用。在内部,monad将执行可能需要的任何错误检查。
罗伯特·哈维

是的,这个问题是关于什么的-为什么它像其他任何东西一样被视为副作用?
shabunc 2011年

2
任何改变外部世界的行为都被视为副作用。
罗伯特·哈维

1

如果未连接到终端设备,或者由于某种原因而关闭了文件描述符,则写入STDOUT可能会失败。

同样,STDOUT并不总是“控制台屏幕”。有时,它通过管道传递到另一个程序。有时管道坏了。


0

如果您用“改变外部世界的状态”来考虑纯净度,那么它会有所帮助。这可能包括写入控制台,日志文件,弹出CD或“发射导弹”。

就并发执行而言,这也是一个问题。如果您知道某个函数没有副作用,则可以轻松安排并发,因为您可以证明不存在竞争条件或类似情况。


更改外部世界的状态取决于外部世界的状态。有关这些方面的更多讨论,请参见此问题
MatrixFrog 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.