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宏中的参数以捕获命名空间_Macros_Clojure_Quoting - Fatal编程技术网

Macros 强制Clojure宏中的参数以捕获命名空间

Macros 强制Clojure宏中的参数以捕获命名空间,macros,clojure,quoting,Macros,Clojure,Quoting,我正在开发Clojure宏,以帮助构建基于GridBagLayout的JPanel。我可以在宏内的默认映射中获取Java类,以限定名称空间,但不能将这些类作为参数传入。我需要什么样的反报价、报价、tildas或其他东西的神奇组合 (import [java.awt GridBagConstraints GridBagLayout Insets] [javax.swing JButton JPanel]) (defmacro make-constraints [gridx gri

我正在开发Clojure宏,以帮助构建基于GridBagLayout的JPanel。我可以在宏内的默认映射中获取Java类,以限定名称空间,但不能将这些类作为参数传入。我需要什么样的反报价、报价、tildas或其他东西的神奇组合

(import [java.awt GridBagConstraints GridBagLayout Insets]
        [javax.swing JButton JPanel])

(defmacro make-constraints [gridx gridy & constraints]
  (let [defaults
        {:gridwidth 1 :gridheight 1 :weightx 0 :weighty 0
         :anchor 'GridBagConstraints/WEST :fill 'GridBagConstraints/NONE
         :insets `(Insets. 5 5 5 5) :ipadx 0 :ipady 0}

        values
        (assoc (merge defaults (apply hash-map constraints))
          :gridx gridx :gridy gridy)]
    `(GridBagConstraints. ~@(map (fn [value]
                                   (if
                                    (or
                                     (number? value)
                                     (string? value)
                                     (char? value)
                                     (true? value)
                                     (false? value)
                                     (nil? value))
                                    value
                                    `~value))
                                 (map values
                                      [:gridx :gridy :gridwidth :gridheight
                                       :weightx :weighty :anchor :fill
                                       :insets :ipadx :ipady])))))
当我使用默认映射中定义的
插入时,它将被限定为
(java.awt.Insets…
):

但当我把它作为一个论点来传递时,它并没有:

user=> (macroexpand-1 '(make-constraints 1 1 :insets (Insets. 2 2 2 2)))
(java.awt.GridBagConstraints.
 1 1 1 1 0 0
 GridBagConstraints/WEST GridBagConstraints/NONE
 (Insets. 2 2 2 2) 0 0)

我不只是想成为一个固执的人。我遇到了编译器错误,无法找到合适的
GridBagConstraints
构造函数。

这是我的解决方案。我正在编写的Swing应用程序中使用它。它已经为我节省了许多行代码编写(针对两个不同的面板),速度将与手写代码一样快

(defmacro grid-bag-container [container & args]
  "Fill and return a java.awt.Container that uses the GridBagLayout.
  The macro defines a set of default constraints for the GridBagConstraints:
    :gridwidth 1
    :gridheight 1
    :weightx 0
    :weighty 0
    :anchor :WEST
    :fill :NONE
    :insets (Insets. 5 5 5 5)
    :ipadx 0
    :ipady 0
  These defaults can be overridden in the call to the macro in two way:
    - If the first argument is a hash-map of constraint names and values
      (e.g.: {:weightx 1}), these will override the defaults for the
      entire container.
    - Each individual item (see below) can override the global defaults
      and container defaults for itself.
  The constraints consist of constraint name (as a keyword with the same
  name as the GridBagConstraints field), and a value, which can also be
  a keyword, in which case the appropriate constant from GridBagConstraints
  will be substituted (e.g.: :NONE == GridBagConstraints.NONE), or the value
  can be an expression (e.g.: 0 or (Insets. 2 2 2 2)).
  Following the optional container default overrides hash-map are one or
  more row specification vectors. Each vector represents one row and
  increments gridy (starting from 0). Each vector contains one or more
  item vectors representing the individual components to be added to the
  container. Each item vector has the component as its first value,
  followed by zero or more constraint overrides as keyword-value pairs.
  (e.g.: [myButton :gridwidth 2 :weightx 1]). The values may be keywords
  and are expanded to GridBagConstraints constants as described above.
  Each item vector gets the next value of gridx (starting with 0) in that
  row.
  For example:
    (grid-bag-container panel
      {:insets (Insets. 1 1 1 1)}
      [[button :gridwidth 2 :weightx 1.0 :fill :HORIZONTAL]]
      [[check-box :gridwidth 2 :weightx 1.0 :anchor :CENTER]]
      [[arrive-label] [arrive-text-field :fill :HORIZONTAL]]
      [[depart-label] [depart-text-field :fill :HORIZONTAL]])
  will expand to the hand-written equivalent:
    (doto panel
      (.add button
        (GridBagConstraints. 0 0 2 1 1.0 0  ; gridx: 0 gridy: 1
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
      (.add check-box
        (GridBagConstraints. 0 1 2 1 1.0 0  ; gridx: 0 gridy: 1
                             GridBagConstraints/CENTER
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add arrive-label
        (GridBagConstraints. 0 2 1 1 0 0    ; gridx: 0 gridy: 2
                             GridBagConstraints/WEST
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add arrive-text-field
        (GridBagConstraints. 1 2 1 1 0 0    ; gridx: 1 gridy: 2
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
      (.add depart-label
        (GridBagConstraints. 0 3 1 1 0 0    ; gridx: 0 gridy: 3
                             GridBagConstraints/WEST
                             GridBagConstraints/NONE
                             (Insets. 1 1 1 1) 0 0))
      (.add depart-text-field
        (GridBagConstraints. 1 3 1 1 0 0    ; gridx: 1 gridy: 3
                             GridBagConstraints/WEST
                             GridBagConstraints/HORIZONTAL
                             (Insets. 1 1 1 1) 0 0))
  @param container the java.awt.Container to fill
  @param args the components and GridBagContraints speicifcations
  @returns the filled Container"
  (let [global-defaults
        {:gridwidth 1
         :gridheight 1
         :weightx 0
         :weighty 0
         :anchor :WEST
         :fill :NONE
         :insets `(Insets. 5 5 5 5)
         :ipadx 0
         :ipady 0}

        [defaults rows]
        (if (map? (first args))
          [(into global-defaults (first args)) (rest args)]
          [global-defaults args])]
    `(doto ~container
      ~@(loop [gridy 0 rows rows ret []]
        (if (seq rows)
          (recur (inc gridy) (rest rows)
            (into ret
              (let [row (first rows)]
                (loop [gridx 0 row row ret []]
                  (if (seq row)
                    (recur (inc gridx) (rest row)
                      (conj ret
                        (let [item
                              (first row)

                              component
                              (first item)

                              constraints
                              (assoc (merge defaults
                                            (apply hash-map (rest item)))
                                :gridx gridx :gridy gridy)

                              constraint-values
                              (map (fn [value]
                                (if (keyword? value)
                                  `(. GridBagConstraints
                                      ~(symbol (name value)))
                                  `~value))
                                (map constraints
                                  [:gridx :gridy :gridwidth :gridheight
                                   :weightx :weighty :anchor :fill
                                   :insets :ipadx :ipady]))]
                          `(.add ~component (new GridBagConstraints
                                                 ~@constraint-values)))))
                    ret)))))
          ret)))))

谢谢,谢谢你的帮助。

我不知道
GridBagLayout
,但是下面的工作原理应该与你的宏类似。如果组件的
:height
大于1,则必须在其下方的列中添加
nil
,以保持列计数器同步。例如,您的
到达文本字段
的高度为2,而您必须在
离开标签
行之前添加一行
nil
,以保持计数器正确。这只是一个快速的破解

(def default-opts
  {:insets   (Insets. 0 0 0 0)
   :width    1
   :height   1
   :weight-x 0.0
   :weight-y 0.0
   :fill     GridBagConstraints/NONE
   :anchor   GridBagConstraints/WEST
   :ipadx    0
   :ipady    0})

(defn grid-bag-constraints
  [x y global-opts opts]
  (let [{:keys [insets width height weight-x weight-h
                fill anchor ipadx ipady]}
        (merge default-opts global-opts opts)]
    (GridBagConstraints. x y width height weight-x weight-h
                         anchor fill insets ipadx ipady)))

(defn grid-bag-container
  [panel global-opts & rows]
  (doseq [[row-idx row] (map-indexed identity rows)
          [col-idx [target & {:as opts}]] (map-indexed identity row)
          :when target]
    (let [constraints (grid-bag-constraints col-idx row-idx global-opts opts)]
      (.add panel target constraints))))

用法与以前一样。

如果调用宏的客户机在其命名空间中导入了
Insets
,则您的宏不需要对其进行限定(通常需要做大量工作)。如果他没有导入
插图
,他就做错了。在我看来,如果用户有权
导入
,那么这两个选项要么都应该编译,要么都不编译。迎合那些没有导入权限的用户只会让所有相关人员流泪;如果它仍然损坏,您能提供更多信息吗?Ralph,您使用的是哪个Java版本和哪个Clojure版本?这两种make约束的调用,包括传递Insets的调用,都适用于我。我正在使用Clojure 1.2.0和Sun Java 1.6.0_24。另一方面,你当地人身上的
#
是误导性的。这意味着它们在扩展上下文中被用作gensym,而实际上它们只是本地人,在宏运行时使用了一个有趣的名称。@amalloy:the
#
s是因为我对
gensym
的理解很差。在您提到它之后,我再次思考并意识到,我需要gensym的唯一符号是那些绑定在宏扩展中的符号(在本例中没有)。我更新了这个问题。@user100464:Java6在OsX上构建26,Clojure1.2。实际上,这个宏是一个更复杂的宏的简化,它实际上构建了整个JPanel。我可能在简化时无意中解决了自己的问题。我再看看我的原稿。
(def default-opts
  {:insets   (Insets. 0 0 0 0)
   :width    1
   :height   1
   :weight-x 0.0
   :weight-y 0.0
   :fill     GridBagConstraints/NONE
   :anchor   GridBagConstraints/WEST
   :ipadx    0
   :ipady    0})

(defn grid-bag-constraints
  [x y global-opts opts]
  (let [{:keys [insets width height weight-x weight-h
                fill anchor ipadx ipady]}
        (merge default-opts global-opts opts)]
    (GridBagConstraints. x y width height weight-x weight-h
                         anchor fill insets ipadx ipady)))

(defn grid-bag-container
  [panel global-opts & rows]
  (doseq [[row-idx row] (map-indexed identity rows)
          [col-idx [target & {:as opts}]] (map-indexed identity row)
          :when target]
    (let [constraints (grid-bag-constraints col-idx row-idx global-opts opts)]
      (.add panel target constraints))))