5

原来的脚本是这样的:

#lang racket
(for ([i (in-range 3)])
    (for ([j (in-range 9)])
      (display "X"))
     (display "\n"))

(for ([i (in-range 6)])
  (for ([j (in-range 3)])
    (display " "))
  (for ([j (in-range 3)])
    (display "X"))
  (for ([j (in-range 3)])
    (display " "))
  (display "\n"))

(for ([i (in-range 3)])
    (for ([j (in-range 9)])
      (display "X"))
     (display "\n"))

输出是:

XXXXXXXXX
XXXXXXXXX
XXXXXXXXX
   XXX   
   XXX   
   XXX   
   XXX   
   XXX   
   XXX   
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX

我想知道是否可以使用这样的 DSL 重写它:

(define a
  "3 9 X
6 3 b 3 X 3 b
3 9 X")

进而:

(interpret a)

绘制此图。

有谁知道最好的方法是什么?

4

2 回答 2

10

要解决这样的问题,首先要描述一种数据类型,它可以在 DSL 中捕获您想要的操作,而不是专注于表面语法。一旦掌握了数据类型,您应该可以更轻松地解决问题。

乍一看,我们可以用您的语言设计 3 种基本形式:

  1. 字符串
  2. 重复
  3. 测序

我们可以用原始字符串和结构来表示这个不相交的类。让我们将这个类作为一个整体称为“pexpr”,即“可打印的 expr”。在代码中:

;; An pexpr is one of the following:
;;   * a primitive string,
;;   * a seq, or
;;   * a repeat
(struct seq (bodies) #:transparent)    ;; bodies is a list of pexpr
(struct repeat (n body) #:transparent) ;; n is a number, body is a pexpr

将一些辅助函数设为缩写可能会有所帮助,因为“seq”和“repeat”本身有点冗长。

;; For convenience, we define some abbreviations s and r for seq and repeat,
;; respectively.
(define (s . bodies)
  (seq bodies))
(define (r n . bodies)
  (repeat n (seq bodies)))

您的示例“I”字符串可以这样写:

(define an-example
  (s
   (r 3 (r 9 "X") "\n")
   (r 6 (r 3 " ") (r 3 "X") "\n")
   (r 3 (r 9 "X") "\n")))

请注意,此编码具有换行符的显式表示,仅从表面语法来看,换行符是隐式的。然后解析器的工作就是在表面语法中提取行并将它们转换为 pexpr,但这应该不会太难。希望。:)

无论如何,解释函数就变成了为这样的模板填写详细信息的问题:

(define (interpret pexpr)
  (match pexpr
    [(? string?)
     ...]
    [(struct seq (bodies))
     ...]
    [(struct repeat (n body))
     ...]))

'...' 应该很容易填写。

这种解决这类问题的方法在如何设计程序编程语言:应用程序和解释中有所描述。我建议看看它们:它们是好东西。

于 2012-09-10T19:15:30.623 回答
2

当然,这看起来可行。这是一个解析问题,主要是。我会像这样打破它。您的每条输入行都指定一个输出行块。在 Racket 中找出一种表示它的好方法。做一些例子,以确保它涵盖了您希望它涵盖的内容。接下来,我可能会编写呈现这些块之一的函数。大多数情况下,我会先做一个,这样我才能满意地看到输出。然后,我会编写一个函数来获取这些块规范的列表并将它们全部输出。然后,我将编写一个解析单行输入的函数。看起来您可以使用空格(例如,使用“regexp-split”)拆分这些行,然后使用临时解析器处理这些列表。这是我认为我最有可能出错的部分,而且我 d 在编码之前编写一堆测试用例。最后,您需要一个函数在输入的每一行上调用此解析器,然后将生成的块规范发送到显示函数。

于 2012-09-10T06:35:51.810 回答