Racket Lisp - 使用 'read' 尝试解析整个输入字符串

Racket Lisp - using 'read' with trying to parse the whole input string

我使用 Racket 中的函数 read 来解析任意输入字符串。 例如,

 >(read (open-input-string "(1 (b 1))")) ; ==> returns '(1 (b 1))

在上面的这个例子中,括号是匹配的——问题出在输入字符串上, 其中括号是unmatched/unbalanced,比如

 > (read (open-input-string "(+ 1 1)(")) ; ==> returns '(+ 1 1)

在这种情况下 read 忽略输入字符串中的最后一个括号 '(' - 我想 read 尝试解析整个输入字符串,或者在不可能时, 因为不匹配的括号,抛出异常。 谢谢。

read过程只从输入端口读取单个数据;额外的括号不会在您的代码中引发错误,因为它永远不会到达。一种解决方案是编写一个从输入端口读取直到到达末尾的过程,将结果形式收集在列表中:

(define (read-from-string s)
  (let ((input (open-input-string s)))
    (let loop ((expr (read input))
               (result '()))
      (if (eof-object? expr)
          (reverse result)
          (loop (read input) (cons expr result))))))

如果read可以成功解析所有表达式,将返回这些表达式的列表;否则将发出错误信号。

交互示例:

scratch.rkt> (read-from-string "(1 (b 1))")
'((1 (b 1)))
scratch.rkt> (read-from-string "(+ 1 2)")
'((+ 1 2))
scratch.rkt> (read-from-string "(+ 1 2) (+ 3 4)")
'((+ 1 2) (+ 3 4))
scratch.rkt> (read-from-string "()")
'(())
scratch.rkt> (read-from-string "(+ 1 1))")
; string::8: read: unexpected `)`
scratch.rkt> (read-from-string "(+ 1 1)(")
; string::8: read: expected a `)` to close `(`