这种声明式 I/O 方法有什么问题(如果有的话)

发布于 2024-09-04 07:32:00 字数 816 浏览 4 评论 0原文

我不确定这在多大程度上属于“编程”而不是“程序语言设计”。但问题是这样的:

比如说,为了简单起见,我们有两个“特殊”列表/数组/向量/任何我们为简单起见而称之为“端口”的东西,一个名为 stdIn ,另一个名为 stdOut。这些在概念上分别表示

  • 在程序持续时间内给予程序的所有用户输入在程序
  • 持续时间内写入终端的所有输出

在受 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!"]

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

I'm not sure exactly how much this falls under 'programming' opposed to 'program language design'. But the issue is this:

Say, for sake of simplicity we have two 'special' lists/arrays/vectors/whatever we just call 'ports' for simplicity, one called stdIn and another stdOut. These conceptually represent respectively

  • All the user input given to the program in the duration of the program
  • All the output written to the terminal during the duration of the program

In Haskell-inspired pseudocode, it should then be possible to create this wholly declarative program:

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

Which would do the expected, ask for two numbers, and print their product. The trick being that stdOut represents the list of strings written to the terminal at the completion of the program, and stdIn the list of input strings. Type errors and the fact that there needs to be some safeguard to only print the next line after a new line has been entered left aside here for simplicity's sake, it's probably easy enough to solve that.

So, before I go of to implement this idea, are there any pitfalls to it that I overlooked? I'm not aware of a similar construct already existing so it'd be naïve to not take into account that there is an obvious pitfall to it I overlooked.

Otherwise, I know that of course:

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

Would be an error if these results need to be interwoven in a similar fashion as above.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

虐人心 2024-09-11 07:32:00

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

  • Hudak, P. 和 Sundaresh, R. 关于纯功能 I/O 系统的表现力。技术。众议员 YALEU/DCS/RR-665,耶鲁大学计算机科学系,1989 年 3 月。Peyton
  • Jones, S. 解决尴尬的问题:单子输入/输出、并发、异常和 Haskell 中的外语调用。载于《软件构造的工程理论》,2002 年,第 47--96 页。

A similar approach was used in early versions of Haskell, except that the elements of the stdin and stdout channels were not strings but generic IO 'actions'--in fact, input and output were generalized to 'response' and 'request'. As long as both channels are lazy (i.e. they are actually 'iterators' or 'enumerators'), the runtime can simply walk the request channel, act on each request and tack appropriate responses onto the response channel. Unfortunately, the system was very hard to use, so it was scrapped in favor of monadic IO. See these papers:

  • Hudak, P., and Sundaresh, R. On the expressiveness of purely-functional I/O systems. Tech. Rep. YALEU/DCS/RR-665, Department of Computer Science, Yale University, Mar. 1989.
  • Peyton Jones, S. Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell. In Engineering theories of software construction, 2002, pp. 47--96.
铃予 2024-09-11 07:32:00

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

The approach you're describing sounds like "Dialogs." In their award-winning 1993 paper Imperative Functional Programming, Phil Wadler and Simon Peyton Jones give some examples where dialogs really don't work very well, and they explain why monadic I/O is better.

笑梦风尘 2024-09-11 07:32:00

考虑到这个示例与您自己的示例相比,我不知道您将如何编织它们:

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 表示来自 stdin 的第 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 替换为您的偏好,也许类似于“同步?”我想不出一个尖锐的词来形容它。

I don't see how you will weave them considering this example compared to your own:

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]]

Should the program prompt for the number represented by stdIn[0] after outputting one line (as in your example) or two lines? If the index 0 represents the 0th input from stdin, then it seems something similar to:

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]]

will be required in order to coordinate the timing of output and input.

I like your idea. Replace some_annotation with your preference, perhaps something akin "synchronize?" I couldn't come up with the incisive word for it.

无边思念无边月 2024-09-11 07:32:00

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

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

如何处理输入和输出
语言没有副作用?在一个
从某种意义上说,输入和输出不是
副作用;可以这么说,他们是
前效和后效。 (...) [程序是]
来自空间的函数
空间的可能输入
可能的输出。

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

(...)

写起来并不难
互动节目(...)[但是]在做
从技术上来说,这也是一种罪过。
(...) 在引用透明的情况下
语言,任何没有明确表达的东西
同步是公平的游戏
以任何顺序进行评估,在
运行时系统自行决定。

(...) 最明显的写法
这个特定的程序是缺点
一起“你好,[名字]!”细绳
在有条件的表达式中
收到换行符后。如果你这样做
这样你就安全了,因为没有
任何评估者都可以证明的方式
提前确保用户将键入
换行符。

(...)

所以没有实际问题
互动软件。尽管如此,
有一些不愉快的事情
这样就可以防止第二种情况的发生。一个
参照透明程序
不应该依赖懒惰
评估以便正常工作。

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

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

This approach seems to be the "most obvious" way to add I/O to a pure λ-calculus, and other people have mentioned that something along those lines has been tried in Haskell and Miranda.

However, I am aware of a language, not based on a λ-calculus, that still uses a very similar system:

How to handle input and output in a
language without side effects? In a
certain sense, input and output aren't
side effects; they are, so to speak,
front- and back-effects. (...) [A program is]
a function from the space
of possible inputs to the space of
possible outputs.

Input and output streams are
represented as lists of natural
numbers from 0 to 255, each
corresponding to one byte. End-of-file
is represented by the value 256, not
by end of list. (This is because it is
often easier to deal with EOF as a
character than as a special case.
Nevertheless, I wonder if it wouldn't
be better to use end-of-list.)

(...)

It's not difficult to write
interactive programs (...) [but] doing
so is, technically speaking, a sin.
(...) In a referentially transparent
language, anything not explicitly
synchronized is fair game for
evaluation in any order whatsoever, at
the run-time system's discretion.

(...) The most obvious way of writing
this particular program is to cons
together the "Hello, [name]!" string
in an expression which is conditioned
on receipt of a newline. If you do
this you are safe, because there's no
way for any evaluator to prove in
advance that the user will ever type a
newline.

(...)

So there's no practical problem with
interactive software. Nevertheless,
there's something unpleasant about the
way the second case is prevented. A
referentially transparent program
should not have to rely on lazy
evaluation in order to work properly.

How to escape this moral dilemma? The
hard way is to switch to a more
sophisticated I/O system, perhaps
based on Haskell's, in which input and
output are explicitly synchronized.
I'm rather disinclined to do this, as
I much prefer the simplicity of the
current system. The easy way out is to
write batch programs which happen to
work well interactively. This is
mainly just a matter of not prompting
the user.

Perhaps you would enjoying doing some programming in Lazy K?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文