2

我不确定这到底有多少属于“编程”而不是“程序语言设计”。但问题是这样的:

说,为了简单起见,我们有两个“特殊”列表/数组/向量/为了简单起见,我们只是称为“端口”,一个称为“端口”,另一个称为“端口stdInstdOut。这些在概念上分别代表

  • 在程序执行期间给予程序的所有用户输入
  • 在程序执行期间写入终端的所有输出

在受 Haskell 启发的伪代码中,应该可以创建这个完全声明性的程序:

 let stdOut =   ["please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

哪个会达到预期,要求两个数字,然后打印他们的产品。诀窍在于 stdOut 表示程序完成时写入终端的字符串列表,而 stdIn 表示输入字符串列表。类型错误以及需要采取一些保护措施才能在输入新行后仅打印下一行的事实为了简单起见将其放在一边,解决这个问题可能很容易。

那么,在我开始实施这个想法之前,有没有我忽略的陷阱?我不知道已经存在类似的构造,因此不考虑我忽略的明显陷阱是天真的。

否则,我当然知道:

 let stdOut =   [stdIn[50],"Hello, World!"]

如果这些结果需要以与上述类似的方式交织在一起,那将是一个错误。

4

4 回答 4

6

在 Haskell 的早期版本中使用了类似的方法,除了 stdin 和 stdout 通道的元素不是字符串而是通用 IO 'actions'——事实上,输入和输出被概括为 'response' 和 'request'。只要两个通道都是惰性的(即它们实际上是“迭代器”或“枚举器”),运行时可以简单地遍历请求通道,对每个请求进行操作并将适当的响应添加到响应通道上。不幸的是,这个系统很难使用,所以它被废弃了,取而代之的是 monadic IO。请参阅这些论文:

  • Hudak, P. 和 Sundaresh, R. 关于纯功能 I/O 系统的表现力。技术。众议员 YALEU/DCS/RR-665,耶鲁大学计算机科学系,1989 年 3 月。
  • Peyton Jones, S. Tackling the Awkward Squad:Haskell 中的单子输入/输出、并发、异常和外语调用。在软件构建的工程理论中,2002 年,第 47--96 页。
于 2010-06-04T00:20:50.747 回答
5

您描述的方法听起来像“对话”。在 1993 年获奖的论文Imperative Functional Programming中,Phil Wadler 和 Simon Peyton Jones 给出了一些对话框确实不能很好地工作的例子,他们解释了为什么单子 I/O 更好。

于 2010-06-04T02:19:15.493 回答
1

与您自己的示例相比,考虑到此示例,我看不出您将如何编织它们:

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number", 
                "and please input another number", 
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

stdIn[0]程序应该在输出一行(如您的示例中)还是两行后提示输入所代表的数字?如果索引0代表来自标准输入的第 0 个输入,那么它看起来类似于:

let stdOut =   ["Welcome to the program which multiplies.",
                "please input a number",
                some_annotation(stdIn[0]),
                "and please input another number", 
                some_annotation(stdIn[1]),
                "The product of both numbers is: " ++ stdIn[0] * stdIn[1]]

将需要协调输出和输入的时间。

我喜欢你的想法。替换some_annotation为您的偏好,也许类似于“同步?” 我想不出一个精辟的词来形容它。

于 2010-06-04T02:27:40.363 回答
1

这种方法似乎是将 I/O 添加到纯 λ 演算中的“最明显”的方法,并且其他人提到在 Haskell 和 Miranda 中已经尝试过类似的方法。

但是,我知道一种语言,不是基于 λ-演算,它仍然使用一个非常相似的系统:

如何在没有副作用的情况下处理语言的输入和输出?从某种意义上说,输入和输出不是副作用;可以说,它们是前后效应。(...) [程序是] 从可能输入空间到可能输出空间的函数。

输入和输出流表示为从 0 到 255 的自然数列表,每个对应一个字节。文件结尾由值 256 表示,而不是由列表结尾表示。(这是因为将 EOF 作为字符处理通常比作为特殊情况更容易。不过,我想知道使用列表结尾是否会更好。)

(...)

编写交互式程序并不难(...)[但是]从技术上讲,这样做是一种罪过。(...) 在引用透明的语言中,任何未显式同步的东西都是公平的游戏,以任何顺序进行评估,由运行时系统自行决定。

(...) 编写这个特定程序的最明显方式是将“你好,[姓名]!”组合在一起。以接收换行为条件的表达式中的字符串。如果你这样做,你是安全的,因为任何评估者都无法提前证明用户会输入换行符。

(...)

所以交互式软件没有实际问题。然而,防止第二种情况的方式有些令人不快。一个引用透明的程序不应该依赖惰性求值来正常工作。

如何摆脱这种道德困境?困难的方法是切换到更复杂的 I/O 系统,可能基于 Haskell 系统,其中输入和输出显式同步。我不太愿意这样做,因为我更喜欢当前系统的简单性。最简单的方法是编写批处理程序,这些程序恰好可以交互地工作。这主要只是不提示用户的问题。

也许您会喜欢在Lazy K中进行一些编程?

于 2010-06-04T14:03:54.747 回答