我一直在阅读有关基于堆栈的编程语言(例如FORTH和Cat),并且看来,鉴于它们的性质,无论它们的范例如何,它们一次只能执行一个动作(FORTH是必不可少的,而Cat是功能性的)。
命令式语言将修改堆栈,而纯功能性语言(如Joy)将返回新堆栈,但要点是一次只能使用一个堆栈。
那么,基于堆栈的编程语言可以并发吗?他们可以通过同时使用多个堆栈或类似方式来实现并发吗?
是否可以在基于堆栈的编程语言中实现惰性评估?
如果我对上述语言和概念有误解,请纠正我
我一直在阅读有关基于堆栈的编程语言(例如FORTH和Cat),并且看来,鉴于它们的性质,无论它们的范例如何,它们一次只能执行一个动作(FORTH是必不可少的,而Cat是功能性的)。
命令式语言将修改堆栈,而纯功能性语言(如Joy)将返回新堆栈,但要点是一次只能使用一个堆栈。
那么,基于堆栈的编程语言可以并发吗?他们可以通过同时使用多个堆栈或类似方式来实现并发吗?
是否可以在基于堆栈的编程语言中实现惰性评估?
如果我对上述语言和概念有误解,请纠正我
Answers:
那么,基于堆栈的编程语言可以并发吗?
当然。
他们可以通过同时使用多个堆栈或类似方式来实现并发吗?
对于普通语言而言,多线程通常意味着拥有多个“调用”堆栈。为每个线程分配自己的数据栈是完全自然的。假设有一个演员,其主体是通过基于堆栈的语言中的代码实现的,那将很简单。GHC par
注释的显式并行性应该相当简单明了。并行执行事物的主要问题是,直到执行代码,您才知道代码的堆栈效果。但是,使用类似Joy的语法,可以想象[a b c] par
执行a b c
要么针对空堆栈,要么针对堆栈的副本,并且仅在完成时保留堆栈的最顶层元素(如果堆栈为空,则推送一些伪值)。您可以想象各种变化。与纯功能语言相比,隐式并行将很难天真地做,但是当然也可以做到。用户定义的组合器的已编译代码通常与“普通”代码没有太大区别。
是否可以在基于堆栈的编程语言中实现惰性评估?
未知的堆栈效果再次成为棘手的部分。如果您设计语言时可以静态确定所有堆栈效果,那么看起来就不太困难了。如果您的懒惰是明确的,那么它似乎也相对简单明了,看起来与Joy的引号和相似i
。据我所知,一种自称懒惰的连接语言的语言似乎在混合了上述两种方法。我真的没有看到隐式的惰性连接语言在动态堆栈效果下如何工作,至少没有以任何可模糊使用的方式工作,但这可能只是我缺乏想象力。
顺便说一句,基于堆栈的语言具有多个堆栈并不少见,例如,Forth有一个数据堆栈和一个返回堆栈,您还可以在它们上面放置任意数据。
我对FORTH有所了解,所以我将仅限于此。它是一种低级语言,使您作为程序员可以访问所有硬件资源。因此,您可以随心所欲。
为了拥有并行程序(编辑:用于表示真正的并发程序),您至少需要两个执行单元(CPU-s)。在FORTH中实现一个单词,例如说“使用这两个参数在处理器2上运行此单词”,将是微不足道的。该单词将在处理器2上分配两个所需的堆栈,并开始运行该单词。您需要对自己可以在该程序中使用的结构进行某种程度的限制。
如果并发程序的数量大于执行单元的数量,则将使用“伪并行”程序。基本上有两种方法可以执行此操作:协程或抢先式多任务处理。在任何情况下,都有可能(不容易,但在文献中有充分描述)如何实现此目标,并且FORTH允许您访问所需的所有低级内容。
当然,您可以像使用任何编程语言一样,在FORTH中执行此操作。它不会像Haskell所说的那样优雅或“内置”。我将使用一个非常幼稚的示例。
这个想法是您定义一个“函数”(在这里宽松地使用)以返回一组东西。一个示例是返回所有整数的函数。然后,您可以对此集合进行操作,完成后给出结果。例如,您可能希望对所有整数求和,直到总和大于1000。非延迟求值首先将所有整数分配为一组,这是不可能的,因为存在无限数量的整数。然后它将开始在此场景上工作。懒惰的实现可能会“给我下一个值”。这样做实际上只需要在功能“最后一个值”中提供一个变量。
Haskell用这种方式做事。当然,它可以处理更复杂的情况,但是想法是相同的。它以一种使您作为程序员的方式专注于评估的方式,而不是解决问题的方式。