簡體   English   中英

清單的球拍模式匹配

[英]Racket pattern matching of lists

我正在嘗試與列表進行模式匹配,但是由於某些原因,當我執行以下操作時會得到意外的匹配:

> (define code '(h1 ((id an-id-here)) Some text here))
> (define code-match-expr '(pre ([class brush: python]) ...))
> (match code
    [code-match-expr #t]
    [_ #f])
#t

問題:為什么codecode-match-expr

實際用例

我在Racket REPL中進行了嘗試,因為我實際上想解決另一個實際問題:使用Pollen的pygments包裝函數突出顯示代碼,這些代碼稍后將以HTML輸出。 為此,我編寫了以下代碼,以解決問題:

(define (read-post-from-file path)
  (Post-from-content (replace-code-xexprs (parse-markdown path))))

(define (replace-code-xexprs list-of-xexprs)
  ;; define known languages
  (define KNOWN-LANGUAGE-SYMBOLS
    (list 'python
          'racket
          'html
          'css
          'javascript
          'erlang
          'rust))
  ;; check if it matches for a single language's match expression
  ;; if it mathces any language, return that language's name as a symbol
  (define (get-matching-language an-xexpr)
    (define (matches-lang-match-expr? an-xexpr lang-symbol)
      (display "XEXPR:") (displayln an-xexpr)
      (match an-xexpr
        [`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
        [`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
        [_ #f]))

    (ormap (lambda (lang-symbol)
             ;; (display "trying to match ")
             ;; (display an-xexpr)
             ;; (display " against ")
             ;; (displayln lang-symbol)
             (matches-lang-match-expr? an-xexpr lang-symbol))
           KNOWN-LANGUAGE-SYMBOLS))

  ;; replace code in an xexpr with highlightable code
  ;; TODO: What happens if the code is in a lower level of the xexpr?
  (define (replace-code-in-single-xexpr an-xexpr)
    (let ([matching-language (get-matching-language an-xexpr)])
      (cond [matching-language (code-highlight an-xexpr matching-language)]
            [else an-xexpr])))

  ;; apply the check to all xexpr
  (map replace-code-in-single-xexpr list-of-xexprs))

(define (code-highlight language code)
  (highlight language code))

在此示例中,我將解析具有以下內容的降價文件:

# Code Demo

```python
def hello():
    print("Hello World!")
```

我得到以下xexpr

1。

(h1 ((id code-demo)) Code Demo)

2。

(pre ((class brush: python)) (code () def hello():
    print("Hello World!")))

但是,由於某種原因,這些都不匹配。

match是語法,不評估模式。 由於code-match-expr是一個符號,它將把整個表達式(評估code結果)綁定到變量code-match-expr並在模式匹配時評估其余的表達式。 結果將始終為#t

請注意,第二個模式符號_相同的模式 它也匹配整個表達式,但是_的特殊之處在於它不會像code-match-expr那樣被綁定。

重要的是,永遠不要使用您定義的變量code-match-expr ,但是由於match綁定了一個具有相同名稱的變量,因此在進行match原始綁定將被遮蓋。

可以正常工作的代碼如下所示:

(define (test code)
  (match code 
    [`(pre ([class brush: python]) ,more ...) #t]
    [_ #f]))

(test '(h1 ((id an-id-here)) Some text here))
; ==> #f

(test '(pre ((class brush: python))))
; ==> #t

(test '(pre ((class brush: python)) a b c))
; ==> #t

正如您所看到的,more ...表示零個或多個,並且忽略哪種括號,因為在Racket []中與(){}

編輯

您仍然有點落后。 在此代碼中:

(define (matches-lang-match-expr? an-xexpr lang-symbol)
  (display "XEXPR:") (displayln an-xexpr)
  (match an-xexpr
    [`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
    [`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
    [_ #f]))

打包模式后,由於未對lang-symbol進行引用,因此它將匹配原子的任何內容,並將其綁定為該子句中的變量。 它與具有相同名稱的綁定變量無關 ,因為match不使用變量,而是創建變量。 您返回變量。 從而:

(matches-lang-match-expr? '(pre ([class brush: jiffy]) bla bla bla) 'ignored-argument)
; ==> jiffy

這是您想要做的事情:

 (define (get-matching-language an-xexpr)
    (define (get-language an-xexpr)
      (match an-xexpr
        [`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
        [`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
        [_ #f]))
    (let* ((matched-lang-symbol (get-language an-xexpr))
           (in-known-languages (memq matched-lang-symbol KNOWN-LANGUAGE-SYMBOLS)))
      (and in-known-languages (car in-known-languages))))

同樣,。 match濫用准引用與創建列表結構完全不同。 它使用它們來匹配文字並將未加引號的符號捕獲為變量。

確保您清楚匹配的內容。 在Racket x表達式中,屬性名稱是符號,但值是字符串。 因此,您要匹配的表達式將類似於(pre ([class "brush: js"])) ___) - 不是 (pre ([class brush: js]) ___)

要匹配該字符串並提取"brush: "之后的部分,可以使用pregexp匹配模式。 這是Frog用於提取要提供給Pygments的語言的代碼段

(for/list ([x xs])
  (match x
    [(or `(pre ([class ,brush]) (code () ,(? string? texts) ...))
         `(pre ([class ,brush]) ,(? string? texts) ...))
     (match brush
       [(pregexp "\\s*brush:\\s*(.+?)\\s*$" (list _ lang))
        `(div ([class ,(str "brush: " lang)])
              ,@(pygmentize (apply string-append texts) lang
                            #:python-executable python-executable
                            #:line-numbers? line-numbers?
                            #:css-class css-class))]
       [_ `(pre ,@texts)])]
    [x x])))

(這里pygmentize是其他Frog源代碼中定義的函數;它是將Pygments作為單獨的進程運行並對其之間進行管道pygmentize的包裝器。但是您可以替代使用Pygments或任何其他語法突出顯示器的另一種方法。對於您來說,這是N / A關於match問題。我只是提到它,以免分散注意力,成為另一個嵌入的問題。:))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM