![](/img/trans.png)
[英]Clojure pattern matching macro with variable arity that goes beyond explicit match cases
[英]Clojure simple pattern matching
作為我上一個問題的后續,我試圖在 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
並綁定到內部變量,並檢查文字符號 ( '<
) 是否實際匹配模式。 也許對於第二種模式( ['< ub]
):
(let [[sym1 ub] pattern]
(if (= '< sym1)
expr1)
我需要使用(gensym)
進行綁定嗎? 如何?
大圖:
(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
案例部分是否為向量的條件。 這種模式匹配應該發生在這種情況下。
我的第一個想法基本上是一樣的:將東西綁定到內部本地人並在一個大的and
. 對於文字,該值綁定到生成的本地; 符號直接在綁定中使用。
我還添加了檢查規范向量是否匹配目標向量的長度。 否則你不能擁有[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))))
希望能幫助您入門。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.