macros - Clojure 简单模式匹配

标签 macros clojure pattern-matching

作为我的 previous question 的后续行动,我正在尝试在 Clojure 中实现一个简单的模式匹配。

我想要以下内容:

(match target
  [ub]    expr1    ; ub should be bound to actual value in expr1
  ['< ub] expr2    ; match the literal less-than symbol
                   ; and ub should be bound to actual value in expr2
  [lb ub] expr3    ; lb and ub should be bound to actual values in expr3
  :else   expr4    ; default case if none match
)

用法:
(match [< 5.0] ...)

应该安排执行expr2在运行时。

我想写一个宏,但我不确定扩展。

我正在考虑将每个 case-and-clause 扩展为 let绑定(bind)到内部变量并检查文字符号 ( '< ) 是否实际匹配模式。也许对于第二种模式( ['< ub] ):
(let [[sym1 ub] pattern]
  (if (= '< sym1)
    expr1)

我需要使用 (gensym)对于绑定(bind)?如何?

大图:
(range-case target
            [0.0 < 1.0] :greatly-disagree
            [< 2.0]     :disagree
            [< 3.0]     :neutral
            [< 4.0]     :agree
            [5.0]       :strongly-agree
            42          :the-answer
            :else       :do-not-care)

我正在尝试匹配 [...]模式并将它们转换为以下内容:
[ub]          (if previous-ub `(and (<= ~previous-ub ~target) (<= ~target ~ub))
                              `(< ~target ~ub))
['< ub]       (if previous-ub `(and (<= ~previous-ub ~target) (< ~target ~ub))
                              `(< ~target ~ub))
[lb ub]       `(and (<= ~lb ~target) (<= ~target ~ub))
['< lb ub]    `(and (< ~lb ~target) (<= ~target ~ub))
[lb '< ub]    `(and (<= ~lb ~target) (< ~target ~ub))
['< lb '< ub] `(and (< ~lb ~target) (< ~target ~ub))

我有一个 cond检查 case 部分是否为向量。这种模式匹配应该发生在这种情况下。

最佳答案

我的第一个想法基本上是一样的:将东西绑定(bind)到内部本地人并在一个大的 and 中测试它们的内容。 .对于文字,该值绑定(bind)到生成的本地;符号直接在绑定(bind)中使用。

我还添加了检查规范向量是否匹配目标向量的长度。否则你不能拥有 [ub]以及 [lb ub]因为两者都不包含可能失败的检查。所以总是会选择第一个。

这是代码:

(defn make-clause
  [expr-g [spec expr & more :as clause]]
  (when (seq clause)
    (let [tests-and-bindings (map (fn [x]
                                    (if-not (symbol? x)
                                      (let [x-g (gensym "x")]
                                        [`(= ~x ~x-g) x-g])
                                      [nil x]))
                                  spec)
          tests    (keep first tests-and-bindings)
          bindings (map second tests-and-bindings)]
      `(let [[~@bindings] ~expr-g]
         (if (and (= (count ~expr-g) ~(count spec)) ~@tests)
           ~expr
           ~(make-clause expr-g more))))))

(defmacro match
  [expr & clauses]
  (let [expr-g  (gensym "expr")]
    `(let ~[expr-g expr]
       ~(make-clause expr-g clauses))))

和一个示例扩展。我没有在示例中使用语法引用来减少扩展中的噪音,但您应该明白这一点。
(let [expr98 [(quote <) 3.0]]
  (let [[ub] expr98]
    (if (and (= (count expr98) 1))
      (if previous-ub
        (and (<= previous-ub target) (<= target ub))
        (< target ub))
      (let [[x99 ub] expr98]
        (if (and (= (count expr98) 2) (= (quote <) x99))
          (if previous-ub
            (and (<= previous-ub target) (< target ub))
            (< target ub))
          (let [[lb ub] expr98]
            (if (and (= (count expr98) 2))
              (and (<= lb target) (<= target ub))
              nil)))))))

调用是:
(match ['< 3.0]
  [ub]    (if previous-ub
            (and (<= previous-ub target) (<= target ub))
            (< target ub))
  ['< ub] (if previous-ub
            (and (<= previous-ub target) (< target ub))
            (< target ub))
  [lb ub] (and (<= lb target) (<= target ub))))

希望能帮助您入门。

关于macros - Clojure 简单模式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6348135/

相关文章:

scala - 如何简化这种模式匹配?

macros - 语法规则中如何使用矢量模式?

c++ - 我可以从静态 const char* 数组定义以下宏 "unstringifying"吗?

clojure - Enlive 模板 – 添加到 head 部分

types - 这个 clojure.core.typed 类型错误是什么意思?

clojure - 惯用的 clojure 从字符串中解析命令行开关和参数

Scala - 数组上的模式匹配不会对丢失的情况发出警告

swift - 你能从调用者那里得到 __FUNCTION__ 吗?

c++ - 如何查看C++宏的内容?

scala - Scala 中嵌套类型的模式匹配