首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >生成cond(测试表达式.)在计划中

生成cond(测试表达式.)在计划中
EN

Stack Overflow用户
提问于 2021-12-31 17:44:31
回答 1查看 61关注 0票数 0

我已经使用了大约一年的Guile,但对于如何在Scheme中使用宏还相当缺乏经验。虽然我有一些更复杂的例子可以令人满意地工作,但我还是被困在(对我来说)感觉是一个非常简单的用例,类似于在C中使用#define可以实现的简单替代。

我有一个函数,它使用cond测试几个条件,有些条件具有通用形式。例如:

代码语言:javascript
复制
(define (file->list filename)
  "Read input and split into list of 
   coordinates and folds."
  (let ((lst (call-with-input-file filename
           (λ (p)
         (list-ec (:port line p read-line)
              (cond
               ((string-any (cut eqv? <> #\,) line)
                (string-split line #\,))
               ((string-null? line) #f) ;; blank line
               ((string= line "fold along x=" 1 13 1 13)
                `(x ,(last (string-split line #\=))))
               ((string= line "fold along y=" 1 13 1 13)
                `(y ,(last (string-split line #\=))))
               (else (error "bad input!"))))))))
    (parse-input lst)))

我想消除以下表格中的重复:

代码语言:javascript
复制
((string= line "fold along x=" 1 13 1 13)
`(x ,(last (string-split line #\=))))

在我看来,这就像一个宏,因为这个样板可以在编译时使用模式匹配生成--我天真地尝试过这样的方法:

代码语言:javascript
复制
(define-syntax-rule (fold-parse str x-or-y)
   `((string= ,str
         ,(string-append "fold along " (symbol->string x-or-y) "=")
         1 13 1 13)
      (x-or-y ,(string->number (last (string-split str #\=))))))

这确实在REPL中再现了(test表达式)s表达式:

代码语言:javascript
复制
scheme@(guile-user)> (fold-parse "fold along x=3" 'x)
$33 = ((string= "fold along x=3" "fold along x=" 1 13 1 13) ((quote x) 3))
scheme@(guile-user)> 

但是,当我试图将宏插入到我的cond中时,我会得到以下错误:

代码语言:javascript
复制
;;; WARNING: compilation of /home/foo/dev/aoc_2021/13/./13.scm failed:
;;; Syntax error:
;;; /home/foo/dev/aoc_2021/13/./13.scm:53:28: source expression failed to match any pattern in form fold-parse
ice-9/psyntax.scm:2794:12: In procedure syntax-violation:
Syntax error:
unknown location: source expression failed to match any pattern in form fold-parse

我天真地把它加在下面--我已经把“沿着x=折叠”样板周围的样板注释掉了,它的意思是要替换:

代码语言:javascript
复制
(define (file->list filename)
  "Read input and split into list of 
   coordinates and folds."
  (let ((lst (call-with-input-file filename
           (λ (p)
         (list-ec (:port line p read-line)
              (cond
               ((string-any (cut eqv? <> #\,) line)
                (string-split line #\,))
               ((string-null? line) #f) ;; blank line
               (fold-parse line 'x)
               ;;((string= line "fold along x=" 1 13 1 13)
               ;; `(x ,(last (string-split line #\=))))
               ((string= line "fold along y=" 1 13 1 13)
                `(y ,(last (string-split line #\=))))
               (else (error "bad input!"))))))))
    (parse-input lst)))

自从这次尝试以来,我已经深入到了一些syntax-casequasisyntax,以及宏和cond上的许多其他变体中,试图使它正常工作。

但是,显然,对于宏可以“插入”代替一个片段或表达式的一部分代替它们的方式,我并没有得到一些基本的重要信息。

有人能帮我看出我的错误吗?

如何编写可以生成测试和表达式以便在cond-clause中使用的宏?那么-这是一种合理/明智的做法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-31 19:18:30

cond将在宏之前展开。因此。

代码语言:javascript
复制
(cond 
  ...
  (fold-parse line 'x)
  ...)

将首先转化为:

代码语言:javascript
复制
(if ...
    (if fold-parse
        (begin line 'x)
        ...)

因此,您可能会得到一个未绑定的变量错误,或者可能是猪飞。无论如何,cond的工作原理是,如果cond项只有一个测试,则真实值将是cond的结果,因此您可以这样做:

代码语言:javascript
复制
(define (handle-fold line var)
  (let ((str (string-append "fold along " (symbol->string var) "=")))
    (and (string= line str 1 13 1 13)
         (list var (last (string-split line #\=))))))

在你身上,cond

代码语言:javascript
复制
(cond
  ((string-any (cut eqv? <> #\,) line)
   (string-split line #\,))
  ((string-null? line) #f) ;; blank line
  ((handle-fold line 'x))  ;; NB: The truthy return is the result
  ((handle-fold line 'y))  ;; NB: The truthy return is the result
  (else (error "bad input!"))))))))

现在,看看代码的数量,它并没有变得简单得多,所以我会对最初的版本感到满意,并且可能开始考虑如果类似的行数进一步增加的话。现在,这两行可能会改变,在未来的版本中会有所不同,并且可能会失去努力。它的发生比我的预测更多地帮助我在未来,但我也喜欢保持干燥。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70544527

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档