Clojure 通过'将类型/fn对熔合成多态fn;匿名';礼宾;方法

Clojure 通过'将类型/fn对熔合成多态fn;匿名';礼宾;方法,clojure,Clojure,我的目标是一个如下工作的函数/宏: (def f (polymorphic-fn java.lang.Long (fn [a] (inc a)) java.lang.String (fn [a] (str a "x")))) (f 1) ;; => 2 (f "abc") ;; => "abcx" (defmacro polymorphic-fn [& pairs] (let [proto (gensym)

我的目标是一个如下工作的函数/宏:

(def f (polymorphic-fn
          java.lang.Long   (fn [a] (inc a))
          java.lang.String (fn [a] (str a "x"))))
(f 1)     ;; => 2
(f "abc") ;; => "abcx"
(defmacro polymorphic-fn
  [& pairs]
  (let [proto  (gensym)
        method (gensym)
        extends (for [[type handler] pairs]
                  `(extend ~type ~proto {(keyword ~method) ~handler}))]
    `(do
       (defprotocol ~proto (~method [e#]))
       ~@extends
       ~method)))
由于基于类型的协议分派具有最好的性能,我想用如下宏为“fused”函数创建一个“匿名”协议:

(def f (polymorphic-fn
          java.lang.Long   (fn [a] (inc a))
          java.lang.String (fn [a] (str a "x"))))
(f 1)     ;; => 2
(f "abc") ;; => "abcx"
(defmacro polymorphic-fn
  [& pairs]
  (let [proto  (gensym)
        method (gensym)
        extends (for [[type handler] pairs]
                  `(extend ~type ~proto {(keyword ~method) ~handler}))]
    `(do
       (defprotocol ~proto (~method [e#]))
       ~@extends
       ~method)))
这会产生错误:
无法解析符号:G_u18707


是否有方法返回“匿名”方法,或者有更好的方法实现这样的功能?

我认为您只需要使用常规协议,以及
扩展类型

(defprotocol Fooable
  (foo [this]) )
(extend-type java.lang.Long
  Fooable
  (foo [some-long] (inc some-long)))
(extend-type java.lang.String
  Fooable
  (foo [any-string] (str any-string "-and-more")))
结果:

(foo 3)        => 4
(foo "hello")  => "hello-and-more"
通过使用auto-gensym,可以使用宏隐藏协议名,但我看不出这有什么意义。只要忽略协议名“Fooable”,就会得到相同的结果

另外,请注意Clojure实现的某些部分在幕后创建了具体的Java类,这可能需要一个硬编码的名称

您还可以使用
cond
模拟协议功能:

(defn bar [it]
  (cond
    (= (class it) java.lang.Long) (inc it)
    (= (class it) java.lang.String) (str it "-and-more")))

(bar 7)            => 8
(bar "farewell")   => "farewell-and-more"

如果需要,您可以定义一个函数来生成
,就像您使用
多态fn
一样。

我想您只需要使用常规协议,以及
扩展类型

(defprotocol Fooable
  (foo [this]) )
(extend-type java.lang.Long
  Fooable
  (foo [some-long] (inc some-long)))
(extend-type java.lang.String
  Fooable
  (foo [any-string] (str any-string "-and-more")))
结果:

(foo 3)        => 4
(foo "hello")  => "hello-and-more"
通过使用auto-gensym,可以使用宏隐藏协议名,但我看不出这有什么意义。只要忽略协议名“Fooable”,就会得到相同的结果

另外,请注意Clojure实现的某些部分在幕后创建了具体的Java类,这可能需要一个硬编码的名称

您还可以使用
cond
模拟协议功能:

(defn bar [it]
  (cond
    (= (class it) java.lang.Long) (inc it)
    (= (class it) java.lang.String) (str it "-and-more")))

(bar 7)            => 8
(bar "farewell")   => "farewell-and-more"

如果需要,您可以定义一个函数来生成
bar
,就像您使用
polymorphic fn
一样。

问题在于
deprotocol
将生成将插入协议方法的代码。在宏扩展之后,编译器仍然不知道您定义的方法的符号。因此,编译失败,并将提示符号未知

许多其他的
def…
将生成一个宏“调用”,该调用将在宏扩展期间插入符号(因此编译器将保持愉快)

要修复它,您只需事先声明即可。这是因为
declare
是宏,将得到扩展,编译器会很高兴:

(defmacro polymorphic-fn
  [& pairs]
  (let [proto (gensym "proto")
        method (gensym "prot-method-")
        extends (for [[type handler] (partition 2 pairs)]
                  `(extend ~type ~proto {~(keyword (str method)) ~handler}))]
    `(do
       (declare ~method)
       (defprotocol ~proto (~method [e#]))
       ~@extends
       ~method)))

注意:我还修复了此中的
关键字
调用。

问题是
defprotocol
将生成将插入协议方法的代码。在宏扩展之后,编译器仍然不知道您定义的方法的符号。因此,编译失败,并将提示符号未知

许多其他的
def…
将生成一个宏“调用”,该调用将在宏扩展期间插入符号(因此编译器将保持愉快)

要修复它,您只需事先声明即可。这是因为
declare
是宏,将得到扩展,编译器会很高兴:

(defmacro polymorphic-fn
  [& pairs]
  (let [proto (gensym "proto")
        method (gensym "prot-method-")
        extends (for [[type handler] (partition 2 pairs)]
                  `(extend ~type ~proto {~(keyword (str method)) ~handler}))]
    `(do
       (declare ~method)
       (defprotocol ~proto (~method [e#]))
       ~@extends
       ~method)))

注意:我还修复了这里的
关键字
调用。

最终目标是一个用于对各种递归方案进行抽象的库,因此分派机制非常关键,而且多方法在这方面不是很好。最终目标是一个用于对各种递归方案进行抽象的库,因此,分派机制非常关键,在这方面,多方法不是很好,
polymorphic fn
只是高级库函数的构建块,部分目的是摆脱样板文件。另一个重要因素是性能,其次是协议的基于类型的分派
polymorphic fn
只是高级库函数的构建块,部分目的是摆脱样板文件。另一个重要因素是性能,而cond与基于类型的协议调度相差甚远