函数式语言中的多线程? (序言)

发布于 2024-08-19 11:07:10 字数 609 浏览 11 评论 0原文

当我的朋友在学校开始学习 Prolog 时,我嘲笑他学习了一门无用的语言。然而,他向我展示了一些我从来不知道可能发生的东西;我想知道这个技术从何而来。

技术是这样的:

permutation(List) :-
    isAMember(X, List),
    deleteFirstElement(X, List, Substring),
    % and so on

在此代码中,isAMember(X, List) 是一个函数,如果 X 位于 List 中,则返回 true。但是,到目前为止,X 尚未定义为变量 - 因此程序将生成一堆新线程,每个线程对应 X 的每个可能值使 isAMember(X, List) true, 并从那里继续。

这使我们能够以我能想象到的最简单、最优雅的方式创建多线程算法。

所以我的问题是:这是 Prolog 特有的,还是所有逻辑和/或函数语言的功能? 另外,我在哪里可以学习更多像这样的令人惊叹的多线程技术 - 这肯定是未来的编程。

When my friend started learning Prolog in school, I made fun of him for learning a useless language. However, he's showed me some stuff I never even knew possible; I want to know where this technique comes from.

The technique is this:

permutation(List) :-
    isAMember(X, List),
    deleteFirstElement(X, List, Substring),
    % and so on

In this code, isAMember(X, List) is a function that returns true if X is in List. However, up to this point X is not defined as a variable - so the program will spawn a bunch of new threads, one for each possible value of X that makes isAMember(X, List) true, and continue from there.

This allows us to create a multi-threaded algorithm in the simplest, most elegant way I could have ever imagined possible.

So my question is: Is this Prolog-specific, or a feature of all logical- and/or functional-languages? Also, where can I learn more amazing multithreading techniques like this - this is surely the future of programming.

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

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

发布评论

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

评论(4

猫腻 2024-08-26 11:07:10

Prolog 的子集称为“Datalog”,仅限于纯逻辑特征(无“剪切”),原则上,证明搜索可以并行完成。但是,您必须小心,因为完整 Prolog 的语义对结果生成的顺序非常敏感,并且一些真正的 Prolog 程序依赖于此。

Haskell 和 Clean 等纯函数语言的情况要好一些——并行计算子表达式总是安全的——但性能方面存在许多挑战。如果您执行极端并行性(每个子表达式),则由于所有开销,您不会获得任何性能提升。目前有前途的方法似乎是

  • 线程(并发Haskell)

  • 数据并行Haskell

  • “Sparks”与parseq 运算符。

并行函数已经存在了近 30 年,人们仍在努力使其表现良好。如果您想了解更多信息,请尝试

  • ACM Haskell 研讨会的最新记录(以及在此之前的 Haskell 研讨会)

  • Arvind 在麻省理工学院的工作,他是该领域的伟大先驱(请参阅他与 R. Nikhil 合着的关于 pH 并行编程的书)

The subset of Prolog known as "Datalog" is restricted to pure logical features (no "cut"), and in principle, the proof search could be done in parallel. However you'd have to be careful because the semantics of full Prolog is quite sensitive to the order in which results are produced, and some real Prolog programs depend on this.

The situation in pure functional languages like Haskell and Clean is a bit better—it is always safe to evaluate subexpressions in parallel—but there are many challenges of performance. If you do extreme parallelism (every subexpression) you don't get any performance gains because of all the overhead. The promising approaches at the moment seem to be

  • Threads (Concurrent Haskell)

  • Data Parallel Haskell

  • "Sparks" with par and seq operators.

The parallel functional stuff has been around for almost 30 years and people are still trying to make it perform well. If you want more information, try

  • Recent proceedings of the ACM Symposium on Haskell (and before that, the Haskell workshop)

  • The work of Arvind at MIT, who was a great pioneer in this area (check out his book with R. Nikhil on parallel programming with pH)

一桥轻雨一伞开 2024-08-26 11:07:10

如果我没记错我的 Prolog,那么您并没有创建线程,而是使用回溯和统一依次尝试 X 的每个可能的实例。这是相当连续的。

编辑:显然有一些实验性的并行序言,例如 Reform Prolog。然而,据我所知,这并不是 Prolog 实现中的规范。

If I remember my Prolog correctly, you aren't creating threads, but instead each possible instantiation of X is tried in turn, using backtracking and unification. It is quite serial.

EDIT: Apparently there are some experimental parallel prologs out there, for example, Reform Prolog. However, this is not the norm in Prolog implementations, as far as I can tell.

我爱人 2024-08-26 11:07:10

isAMember(X, List) 不会创建线程,prolog 逻辑仅严重依赖于递归和回溯,并且非常程序化,除非您显式创建线程。

isAMember(X, List) 而言,您正在查看统一概念。该函数将与将该函数计算为 true 的所有值(在本例中为列表中包含的所有元素)统一。并继续使用 X 执行。

一旦执行到达叶子,它将回溯到最早可能的“仍然无法统一”的调用(或者切点,我认为,不记得正确的术语),说 isAMember(X, List),将把 X 统一到下一个候选者,并恢复执行。

我敢说,如果你的逻辑不小心,你很容易就会出现堆栈溢出。

isAMember(X, List) will not create threads, prolog logic just relies heavely on recursion and backtracking and is quite procedural unless you explicitly create threads.

In the case of isAMember(X, List), you're looking at the unification concept. that function will unify with all values that evaluates that function to true, in this case, all elements contained in the list. And proceed with the execution with X.

Once the execution has reached a leaf, it will backtrack to the earliest possible "still-unifiable" call (or cut-point, I think, can't remember the correct term), say isAMember(X, List), will unify X to the next candidate, and resume execution.

Dare I say, if you're not careful in your logic, you can easely get stack overflows.

折戟 2024-08-26 11:07:10

老实说,您所展示的内容似乎与列表理解没有任何不同,可能与 foreach 结合使用:

foreach {x | x in List}
    deleteFirstElement(x, List, Substring) 
    // not sure what deleteFirstElement does, so...

正如您提到的 isAMember 可以是任何东西,列表理解也可以更复杂

foreach {x | x in List if x % 2 == 0} // ie, even elements of List

沿着同样的路线,您可以做同样的事情没有列表理解的东西

new_list = old_list.every { x | x % 2 == 0 }

可以很容易地分解成线程。

Honestly, what you've shown doesn't seem any different from a list comprehension, possibly combined with a foreach:

foreach {x | x in List}
    deleteFirstElement(x, List, Substring) 
    // not sure what deleteFirstElement does, so...

As you mentioned that isAMember could be anything, List Comprehension can be more complicated also

foreach {x | x in List if x % 2 == 0} // ie, even elements of List

Along the same lines, you can do the same thing without list comprehension

new_list = old_list.every { x | x % 2 == 0 }

which can be broken into threads just as easy.

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