【问题标题】:What is Predicate Dispatch什么是谓词调度
【发布时间】:2018-03-11 05:07:16
【问题描述】:

我最近看到很多关于 Clojure 中的谓词调度的讨论,我想知道这件事是否有什么问题。换句话说,什么是谓词调度,它与泛型函数、OOP 多态性和模式有何不同? 谢谢

【问题讨论】:

    标签: oop clojure predicate


    【解决方案1】:

    谓词调度包含泛型函数、OOP 多态性、模式匹配等。 Michael Ernst、Craig Kaplan 和 Craig Chambers 的 Predicate dispatching: A unified theory of dispatch 是一个很好的概述。摘自其摘要:

    谓词分派通过允许任意谓词来控制方法的适用性并通过使用谓词之间的逻辑含义作为覆盖关系来概括以前的方法分派机制。选择用于处理消息发送的方法不仅取决于参数的类(如在普通的面向对象调度中),还取决于子组件的类、参数的状态以及对象之间的关系。

    【讨论】:

    • 永远不要使用“subsumes”这个词
    【解决方案2】:

    已编辑: Clojure 多方法不是谓词调度。

    在传统的面向对象编程中,多态性意味着您可以拥有一个方法的多个实现,而被调用的确切实现取决于您调用该方法的对象的类型 .这是类型调度

    Clojure multimethods 对此进行了扩展,以便任意函数可以决定调用哪个实现。在Clojure 形式(defmulti name f) 中,函数fdispatch 函数

    dispatch 函数可以是class,在这种情况下,您将返回键入 dispatch。但该功能可以是其他任何功能:计算调度值、在数据库中查找内容,甚至调用 Web 服务。

    真正的谓词调度可能允许每个方法实现指定一个或多个调度函数(谓词)来决定何时应用该方法。这比多方法更通用,但实现起来更复杂。 Clojure 不支持它。

    泛型函数是来自其他 Lisps 的术语。例如,Common Lisp 提供了generic functions,它可以根据类型以及一组受限的其他函数进行调度。

    【讨论】:

    • Clojure 没有适当的谓词调度系统。调度函数是硬连线的 - 潜在的扩展程序无法添加原始调度函数尚未定义的新调度条件。
    • 除非dispatch函数本身是一个multimethod!但确实不能添加新的调度函数。
    • 我发现这是一个误导性的答案,因为多方法并不是真正的谓词调度。
    • 我觉得是这样的:single dispatch -> multiple dispatcg -> predicate dispatch,从不太通用到更通用。
    • StackOverflow 不允许我删除我的“已接受”答案,因此我将其编辑为(希望)更正确。下面的其他答案更好。
    【解决方案3】:

    谓词调度是一种根据函数参数的数量、“形状”和值对函数调用提供不同响应的方法。 Clojure 函数已经根据传递给函数的参数数量分派给不同的代码体:

    (defn my-func
      ([a] (* a a))
      ([a b] (* a b)))
    

    Clojure 多方法增加了根据分派函数的返回值分派到不同方法(可能定义在不同的命名空间中)的能力,该分派函数检查参数(可以包括它们的编号、类和值)并识别哪个方法给大家。正如 Stuart Sierra 回答的脚注中所指出的,多方法的创建者可以定义调度函数,并且通常不能对其进行修改。此外,程序员必须为一个函数手动设计一个超复杂的调度函数,该函数对 0 的整数执行一件事,对正整数执行另一件事;或者一件事用于一个或多个项目的列表,另一件事用于空列表。

    谓词调度将(也许)提供一种语法来生成这个复杂的调度函数本身。例如,可以这样定义阶乘函数

    (defmatch fact [0] 1)
    (defmatch fact [n] (* n (fact (dec n))))
    

    前面的代码响应调用

    (fact 0)
    

    后一个代码调用带有任何其他值的单个参数的调用。这将(在幕后)定义一个带有分派函数的多方法,该函数将零与其他值区分开来。

    但后来我可以通过编码指定我想要一个地图的阶乘(也许)

    (defmatch fact [x {}] (fact (:value x)))
    

    并且代码可以(理论上)拦截将映射传递给事实的调用,将其他调用委托给原始调度函数......所有这些都在幕后。

    【讨论】:

    • 如果有一种机制,当 (fact 3) 被调用时,该方法可以通过添加 (defmatch fact [3] 6 )
    • 嗯,那将是谓词调度之上的 memoization;如有必要,它可以很容易地(由程序员)添加到(fact [n]),但可能没有理由将它构建到谓词调度机制中(毕竟,不能保证你已经定义了一个纯函数)。跨度>
    【解决方案4】:

    为了对比谓词调度和多方法,有点像你定义了多方法而不指定调度 fn:

    (defmulti my-method)
    

    而且,当你想扩展它时,你不需要指定一个 dispatch 值(因为没有 disaptch fn 来产生它)而是一个谓词:

    (defmethod my-method (fn [a b] (and (vector? a) (vector? b)))
      [a b]
      (do something))
    

    简单而强大。

    问题是谓词可能重叠,而且您不想在每次调用时检查所有可能的谓词。这就是为什么实现会限制谓词的表达能力(类似于模式案例)以便能够智能地处理它们(检测歧义,创建快速决策树等)。

    【讨论】:

    • 嗯,我想知道你是否可以将谓词调度与隐式参数和隐式强制合并,当与 Lisp 的条件系统混合时会导致“交互式编程”。
    猜你喜欢
    • 2021-08-01
    • 2015-01-10
    • 1970-01-01
    • 2011-08-20
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2021-04-19
    • 1970-01-01
    相关资源
    最近更新 更多