Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros Clojure';s宏-定义名称由参数组成的绑定_Macros_Clojure_Metaprogramming - Fatal编程技术网

Macros Clojure';s宏-定义名称由参数组成的绑定

Macros Clojure';s宏-定义名称由参数组成的绑定,macros,clojure,metaprogramming,Macros,Clojure,Metaprogramming,好的,我想编写一个Clojure宏,它定义一个结构映射,并让调用方为每个字段指定类型 签名将如下所示: (defmodel category :id Integer :name String) 它的作用是创建一个名为category的结构映射,并创建一个绑定*category meta*,它是一个映射{:id Integer:name String} 以下是我实现这一目标的宏: (defmacro defmodel [name & field-spec] `(let [fiel

好的,我想编写一个Clojure宏,它定义一个结构映射,并让调用方为每个字段指定类型

签名将如下所示:

(defmodel category :id Integer :name String)
它的作用是创建一个名为category的
结构映射
,并创建一个绑定
*category meta*
,它是一个映射{:id Integer:name String}

以下是我实现这一目标的宏:

(defmacro defmodel [name & field-spec]
    `(let [fields# (take-nth 2 ~@field-spec)]
        (defstruct ~name fields#)
        (def *~name-meta* (reduce #(assoc %1 (first %2) (last %2))) (partition 2 ~@field-spec))))
但是,问题是,我无法定义一个名称由另一个名称组成的绑定。基本上,
(def*~name meta*..)
不起作用

我怎样才能做到这一点

谢谢。

(使用问题文本中的宏调试版本进行更新。)

这应按规定进行:

(defmacro defmodel [name & field-spec]
  `(do (defstruct ~name ~@(take-nth 2 field-spec))
       (def ~(symbol (str "*" name "-meta*"))
         (reduce #(assoc %1 (first %2) (last %2))
                 {}
                 (partition 2 '~field-spec)))))
主要问题的答案是使用
~(symbol(str“*”name“-meta*”)
代替
*~name meta*
~
以语法引号形式取消下一个表达式的引号,将其返回值注入给定列表结构的适当位置

其他一些修改是必要的——特别是,
defstruct
要求将键作为单独的参数提供给它,而不是一个seq(或包含这样一个seq的变量的名称),
reduce
需要显式的种子值在这里工作,等等


顺便说一句,除非您需要坚持Clojure 1.1,否则您可能希望使用1.2的
defrecord
,而不是
defstruct
——事实上,后者在1.2中已被弃用。

感谢您的明确回答。我以前看过defrecord,但主要缺点是必须在初始化时提供所有字段值。e、 例如,(defrecord category[^String id^String name]),我必须像这样调用它
(category.1“stack”)
。我不能执行(category.{:id 1:name“Stack”})或(category.1)之类的操作,即允许使用默认参数。似乎记录支持仍然是暂时的,可能随时改变。请随时插手告诉我关于我到目前为止还没有的任何记录:)我会考虑写一个承包商来做你想做的事情。记录速度更快,并且可以实现协议。在@entootcas中可以找到一些更强大的记录:我不认为记录支持是暂时的——毕竟结构映射确实已经被弃用了,建议使用记录作为替代。(这并没有说明工厂函数的某些约定将来可能会进入核心库。)至于您的具体问题,我基本上同意nickik的观点。(事实上,我发现为我的几乎所有记录编写工厂函数非常有用,只要能够
:以后需要
:导入
-屏蔽所有记录即可。)@nickik:感谢链接@恩图卡斯:哦,还有一件事。在Clojure中,与结构映射或记录相比,使用普通ol映射通常是非常有意义的。你考虑过吗?(加上执行
assoc
&Co.工作的自定义函数,可能在对
*foo meta*
变量执行数据类型检查时。)@Michal,我认为结构映射是带有预定义键的映射,不是吗?