clojure宏来生成函数 [英] clojure macro to generate functions

查看:176
本文介绍了clojure宏来生成函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个将生成n个函数的宏。这是我到目前为止:

 ;只定义这个,因为如果我内联这到make-placeholder 
;它不能扩展i#in〜(symbol(str_i#))
(defmacro defn-from [str mdata args& body]
`(defn〜(symbol str)〜mdata 〜args〜@ body))

;使用列表推导生成n个函数
(defmacro make-placeholders [n]
`(for [i#(range 0〜n)](defn-from(str_i#){ placeholder true} [& args](nth args i#))))

;扩展函数_0 ... _9
(make-placeholders 9)

是:

  java.lang.ClassCastException:clojure.lang.Cons不能转换为java.lang.String 

我不确定这是什么意思,但我有这个模糊的概念

解决方案

你对运行时和编译之间的区别感到困惑,时间,宏和函数之间。使用 eval 解决宏问题从来不是 1 正确的答案,而是确保返回的代码能够实现你想要的结果。



主要的更改是:


  1. defn-from 是一个函数,而不是一个宏 - 你只是想方便地创建列表,主宏负责插入结果形式。您不想在这里想要一个宏,因为您不想将它扩展到 make-placeholders 的正文中。

    li>
  2. make-placeholder do 开头, code> for outside 。这是最重要的部分:你希望返回给用户的代码看起来像(do(defn ...)),就好像他们键入所有

    $ b






 (defn defn-from [str mdata args& body] 
`(defn〜(symbol str)〜mdata〜args〜@ body))

;使用列表推导生成n个函数
(defmacro make-placeholders [n]
(cons'do
(for [i(range 0 n)]
(defn-from str_i){:placeholder true}
'[& args]
`(nth〜'args〜i)))))

user> ($)
(do(clojure.core / defn _0 {:placeholder true} [& args](clojure.core / nth args 0))
clojure.core / defn _1 {:placeholder true} [& args](clojure.core / nth args 1))
(clojure.core / defn _2 {:placeholder true} [& args] core / nth args 2)))

1 / p>




编辑



通过使用函数创建函数并使用低级操作 intern 而不是 def 。事实证明是更简单,事实上:

 (letfn [(placeholder [n] 
(fn [ & args]
(nth args n))]
(doseq [i(range 5)]
(intern * ns * $ b(placeholder i))))


I'm trying to write a macro that will generate n functions. Here's what I have so far:

; only defined this because if I inline this into make-placeholders
; it's unable to expand i# in  ~(symbol (str "_" i#))
(defmacro defn-from [str mdata args & body]
    `(defn ~(symbol str) ~mdata ~args ~@body))

; use list comprehension to generate n functions
(defmacro make-placeholders [n] 
    `(for [i# (range 0 ~n)] (defn-from  (str "_" i#) {:placeholder true} [& args] (nth args i#))))

; expand functions _0 ... _9
(make-placeholders 9)

The error I get is:

java.lang.ClassCastException: clojure.lang.Cons cannot be cast to java.lang.String

And I'm not really sure what that means, but I have this vague notion that (for ...) isn't working the way I think it is inside a macro.

解决方案

You are getting confused about the distinction between runtime and compile-time, and between macros and functions. Solving a macro problem with eval is never1 the right answer: instead, make sure that you return code that does what you want to happen. Here's a minimal change to make your original version work.

The main changes are:

  1. defn-from is a function, not a macro - you just want a convenient way to create lists, which the main macro is responsible for inserting into the result form. You do not want a macro here, because you don't want it expanded into the body of make-placeholders.

  2. make-placeholders starts with a do, and does its for outside of a syntax-quote. This is the most important part: you want the code returned to the user to look like (do (defn ...)), as if they'd typed it all in by hand - not (for ...), which could only ever def a single function.


(defn defn-from [str mdata args & body]
    `(defn ~(symbol str) ~mdata ~args ~@body))

; use list comprehension to generate n functions
(defmacro make-placeholders [n]
  (cons `do
        (for [i (range 0 n)]
          (defn-from (str "_" i) {:placeholder true}
            '[& args]
            `(nth ~'args ~i)))))

user> (macroexpand-1 '(make-placeholders 3))
(do (clojure.core/defn _0 {:placeholder true} [& args] (clojure.core/nth args 0)) 
    (clojure.core/defn _1 {:placeholder true} [& args] (clojure.core/nth args 1)) 
    (clojure.core/defn _2 {:placeholder true} [& args] (clojure.core/nth args 2)))

1 Very, very rarely


Edit

You can also do this completely without macros, by using a function to create functions and using the lower-level operation intern instead of def. It turns out to be much simpler, in fact:

(letfn [(placeholder [n]
          (fn [& args]
            (nth args n)))]
  (doseq [i (range 5)]
    (intern *ns* (symbol (str "_" i))
            (placeholder i))))

这篇关于clojure宏来生成函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆