【问题标题】:Multithreading in... functional languages? (Prolog)多线程……函数式语言? (序言)
【发布时间】:2010-02-01 03:40:30
【问题描述】:

当我的朋友在学校开始学习 Prolog 时,我取笑他学习了一种无用的语言。然而,他向我展示了一些我什至不知道可能的东西;我想知道这种技术是从哪里来的。

技术是这样的:

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

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

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

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

【问题讨论】:

  • 我会说编程是这样开始的!非确定性图灵机有这个概念。
  • Prolog 不是功能语言。它专门解决逻辑问题。

标签: multithreading functional-programming prolog logic-programming


【解决方案1】:

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

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

  • 线程(并发 Haskell)

  • 数据并行 Haskell

  • 带有parseq 运算符的“Sparks”。

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

  • ACM 研讨会 Haskell 近期会议记录(以及之前的 Haskell 研讨会)

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 这是特定于实现的。逻辑编程很容易分成线程,因为它不像面向对象/过程编程那样依赖全局状态。
    • 是的,你是对的,而且有一些是并行的。更新了我的答案。
    【解决方案3】:

    isAMember(X, List) 不会创建线程,prolog 逻辑只是严重依赖递归和回溯,除非您显式创建线程,否则它是非常程序化的。

    对于isAMember(X, List),您正在查看统一概念。该函数将与将该函数评估为真的所有值统一,在这种情况下,列表中包含的所有元素。然后用 X 继续执行。

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

    我敢说,如果你在逻辑上不小心,你很容易导致堆栈溢出。

    【讨论】:

    • 这个 "回溯" 听起来非常像 "emulating multi-threading" - 这是语言的核心部分,还是只是最流行的 Prolog 实现?
    • 使用变量统一的回溯是 prolog 编程的核心。
    【解决方案4】:

    老实说,您显示的内容似乎与列表理解没有什么不同,可能与 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 }
    

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

    【讨论】:

      猜你喜欢
      • 2010-10-25
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-28
      • 2013-07-23
      • 1970-01-01
      相关资源
      最近更新 更多