【问题标题】:Clojure: How to create a function at runtimeClojure:如何在运行时创建函数
【发布时间】:2009-12-01 09:09:38
【问题描述】:

我想完全在运行时生成一个 fn(即名称和 arg 符号是在运行时决定的,而不是在代码中) 实现这一目标的最佳方法是什么?

例如如何实现以下功能?

(defn gen-fn [name arg-symbols body]
...
...

会这样使用:

(gen-fn "my-func-name" (symbol "x") (symbol "y") (println "this is body. x=" x))

注意函数名、参数和函数体没有编码,但可以在运行时决定

【问题讨论】:

    标签: functional-programming clojure


    【解决方案1】:
    (defn gen-fn
      [n as b]
      (let [n        (symbol n)
            as       (vec (map symbol as))
            fn-value (eval `(fn ~n ~as ~b))]
        (intern *ns* n fn-value)))

    还有一些用途:

    user=> (gen-fn "foo" ["x"] '(do (println x) (println (inc x))))
    #'user/foo
    user=> (foo 5)
    5
    6
    nil

    但是,我不太喜欢这种方法。闻起来真的很难闻:eval。为什么要在运行时生成全局变量?我看到错误的命名空间和其他丑陋的问题即将出现......

    【讨论】:

    • 是的。这是丑陋的东西。我需要这个的原因是我正在 Clojure 下尝试遗传编程。 Clojure 似乎很自然。
    • 啊。行。 GP 可能是eval 的合法使用。但仍然对eval 的奇怪效果保持警惕。
    • 为什么要评估?你不能用宏来做这个吗?
    • 不,宏在编译时运行,而不是在运行时。
    • 很好的答案。我只想补充一点,如果目的是基因编程,那么将生成的函数直接存储在映射中而不是将它们添加到命名空间可能是有意义的(这可能会让人感到困惑,因为它是一大块可变状态......)
    【解决方案2】:

    另一种方法是使用“eval”和“read-string”:

    user=> (def f1 (eval (read-string "(fn [x y] (* x y))")))

    #'user/f1

    用户=> (f1 3 5)

    15

    【讨论】:

      【解决方案3】:

      我不完全确定,但我相信您可以使用优于 eval 的宏来做到这一点。

      (defmacro gen-fn
        [n as b]
        (let [n  (symbol n)
              as (vec (map symbol as))]
          `(intern *ns* n (fn ~n ~as ~@b))))
      

      【讨论】:

      • 这在运行时不起作用。重点是:你需要提前知道nasb。然后你可以这样做:(defmacro gen-fn [n as b] (defn ~(symbol n) ~(vec (map symbol as)) ~@b))</code>. With the eval-approach the arguments to gen-fn` 可以是任意计算的结果。
      猜你喜欢
      • 2016-12-09
      • 2012-12-28
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      • 1970-01-01
      • 2017-10-09
      • 1970-01-01
      • 2011-01-28
      相关资源
      最近更新 更多