具有类型提示的动态功能

Lam*_*der 2 metadata eval clojure dynamic

我正在尝试使用提示参数在运行时生成函数.

参数符号在运行时期间是已知的.

如果我事先知道它们,我可以像这样动态创建函数:

(def foo 
  (eval 
    (list 'fn '[^String a] (list '.length 'a))))
Run Code Online (Sandbox Code Playgroud)

具有理想的性能:

user=> (time (reduce + (map foo (repeat 1000000 "asdf")  )))
"Elapsed time: 164.578 msecs"
4000000
Run Code Online (Sandbox Code Playgroud)

而不是:

(def bar
  (eval 
    (list 'fn '[a] (list '.length 'a))))

user=> (time (reduce + (map bar (repeat 1000000 "asdf")  )))
"Elapsed time: 2392.271 msecs"
4000000
Run Code Online (Sandbox Code Playgroud)

现在.我遇到的问题是如何使用动态参数列表在运行时创建这样的函数.例如:

(def baz
  (let [args '[a b]]    
    (eval
      (list 
        'fn 
        (vec (flatten (map (fn [ar] `[^String ~ar]) args))) 
        (list '.length (first args))))))
#'user/baz

user=> (time (reduce + (map baz (repeat 1000000 "asdf") (repeat 1000000 "asdf"))))
"Elapsed time: 2467.178 msecs"
4000000
Run Code Online (Sandbox Code Playgroud)

看起来语法引用会阻止编译器或读取器宏解释类型提示.如何使用类型提示实现动态函数生成?

PS我知道这样的函数创建看起来很疯狂,并且可能建议使用宏而不是eval,但我有充分理由这样做.

PPS除了使用特殊形式'fn'和eval之外,还有其他方法可以创建运行时已知参数的lambda吗?

A. *_*ebb 6

如果你坚持:

(defn bazy [arglist]
  (let [args (mapv #(with-meta (symbol %) {:tag 'String}) arglist)]
    (eval (list 'fn args (list '.length (first arglist))))))

(def baz (bazy '[a b]))
Run Code Online (Sandbox Code Playgroud)