【问题标题】:How do you convert a expression into a predicate? (Clojure)如何将表达式转换为谓词? (Clojure)
【发布时间】:2012-09-16 01:57:37
【问题描述】:

鉴于我有表格的表达方式

'(map? %)

我如何将它转换成类似的东西

'#(map? %)

这样我最终可以将其扩展为类似

'(apply #(map? %) value)

我认为我应该以某种方式使用宏,但不确定如何使用。

【问题讨论】:

  • 您的意思是您将(map? %) 存储为数据,即作为具有两个符号的列表?
  • 是的,我真的想在宏中做到这一点,我想我会引用所有内容来表明我想要什么。

标签: clojure expression predicate


【解决方案1】:

# 调用读取器宏,读取器宏扩展发生在正常宏扩展发生之前。因此,要执行您提到的操作,您需要使用read-string 在您的宏中通过阅读器,如下所示。

(defmacro pred [p v] 
     (let [s# (str \# (last p))] 
         `(apply ~(read-string s#) ~v)))



user=> (pred '(map? %) [{}])
true
user=> (pred '(map? %) [[]])
false

如果数据(即谓词表达式)在运行时可用,那么您需要使用函数(比宏更灵活)。

(defn pred [p v] 
   (let [s (read-string (str \# p))] 
      (eval `(apply ~s ~v))))

user=> (map #(pred % [12]) ['(map? %)'(even? %)])
(false true)

【讨论】:

  • ...但是为什么要使用阅读器宏呢?为什么不直接使用fn
  • 可能是因为他希望输入谓词没有 fn 签名并使用 %1 %2 等作为参数名称。这个问题非常具体,并不能提供整体情况,这可能会导致更好的整体解决方案
  • 好点,我没有看到,因为他的源数据包含对% 的引用,它似乎旨在与#(...) 一起使用。
  • 哇,很有趣。我确定我遗漏了一些东西,因为我无法弄清楚如何使用正常的宏机制将 # 放在适当的位置。我问这个的原因是因为我注意到 prepost-args 中的 :post 键?在 defn 参数列表中采用表达式向量。我很好奇表达式是如何被评估的,因为它们被声明为表达式,而不是匿名函数。
【解决方案2】:

#(...) 是一个阅读器宏。我认为您不能使用阅读器宏生成表达式。例如'#(map? %) 会自动扩展为(fn* [p1__352#] (map? p1__352#)) 或类似的东西。

这是其他阅读器宏上的 relevant discussion

是否可以更改谓词的格式?如果它看起来像这样:

'([arg1] (map? arg1))

那么,将其构造成一个函数将是微不足道的:

(cons 'fn '([arg1] (map? arg1)))

(def pred (eval (cons 'fn '([p](map? p)))))
#'predicate.core/pred

(pred {})
true

(pred 10)
false

现在请不要因为我接下来要发布的内容而讨厌我。我写了一个过于简化的函数阅读器宏:

(defn get-args [p]
  (filter #(.matches (str %) "%\\d*")
          (flatten p)))

(defn gen-args [p]
  (into [] 
        (into (sorted-set) 
              (get-args p))))

(defmacro simulate-reader [p]
  (let [arglist (gen-args p)
        p (if (= (str (first p)) "quote")
            (second p)
            p)]
    (list 'fn (gen-args p) p)))

使用起来非常简单:

((simulate-reader '(map? %)) {}) ; -> true
; or without quote
((simulate-reader (map? %)) {})

; This also works:
((simulate-reader '(+ %1 %2)) 10 5) ; -> 15

与@Ankur 给出的其他解决方案的区别是:

  1. 我不喜欢我的。我只是觉得这是一件有趣的事情。
  2. 不需要转换为字符串,然后对其应用阅读器宏。

【讨论】:

    猜你喜欢
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    相关资源
    最近更新 更多