【问题标题】:Converting a Scheme expression to a string将 Scheme 表达式转换为字符串
【发布时间】:2010-12-12 03:35:10
【问题描述】:

给定一个表达式 '(lambda (x) x) 我怎样才能把它翻译成一个字符串。我认为符号->字符串可以完成这项工作,但它不能不是符号。

例如对于一个宏到字符串: (to-string (lambda(x) x)) 这应该返回 >> "(lambda (x) x)"

大家有什么想法谢谢

【问题讨论】:

  • 只是澄清一下我正在处理引用列表。我会遍历列表并执行字符串连接,但后来我不知道如何处理可变参数 e,g '(lambda (x . y) (display x)(display y))
  • 您使用的是哪种方案?是兼容 R6RS,还是只兼容 R5RS?

标签: string macros lambda scheme expression


【解决方案1】:

你应该通过conses。当一个新的cons开始写“(”,当它结束写“)”并使用symbol->string作为conses内的符号。

您可以使用类型调度来扩展它。方案中是否也存在漂亮的印刷品?

【讨论】:

  • 感谢 Trickster 的快速响应。我也想到了这个解决方案,但后来我不知道如何处理可变参数函数的情况,例如 '(lambda (x . y) (+ x y)) 如何真正知道 .在 x 和 y 之间并输出 "(lambda (x . y) (+ x y)) "
  • 嗯,(x y) 是 (cons x (cons y nil)) 并且 (x . y) 是 (cons x y)
【解决方案2】:

使用pretty-format:

(pretty-format v [columns]) → string?

【讨论】:

  • 不幸的是,我使用的方案实现没有实现漂亮格式:(还有其他选择吗?
【解决方案3】:

表达式'(lambda (x) x) 是一个带引号的列表。

表达式(lambda (x) x) 是某种编译的、不透明的、可执行的运行时内部对象。

symbol->string 只是将符号转换为字符串,即字符序列。

如果您正在使用列表,您可以简单地遍历列表并将各个组件打印出来。事实上(write '(lambda (x) x)) 只会将列表打印出来。

许多方案都有类似于(with-output-to-string ... ) 的东西,它返回写入标准端口的所有输出的字符串。

但是,如果您使用(write (lambda (x) x)),您将得到谁知道是什么。转储可执行函数类型时,您将获得实现提供的任何内容。有些人可能会打印显示源代码的“反汇编”。其他人可能只是打印#function 或同样没用的东西。

简而言之,如果你只是想打印一个列表,有各种各样的机制。

如果你想打印出编译函数的源代码,那是一个完全不同的问题,非常依赖于实现,而且很可能是不可能的。

【讨论】:

    【解决方案4】:

    标准方案(至少在 R5RS 意义上)没有办法做到这一点,所以如果你想要可移植的代码,你需要自己走结构。乏味,但不太复杂(即使对于点列表)。 但是,如果您只想要一些 工作版本,那么您应该查看您的实现手册并寻找执行此操作的方法。答案几乎总是很简单,例如,在 PLT Scheme 中你会使用 (format "~s" '(lambda ...))

    【讨论】:

    • 这个答案是正确的,尽管使用支持 SRFI 6 的实现,你可以只创建一个输出字符串端口,然后 write 到它。
    • 重点是在某些情况下直接这样做会更有效率。如果你要走 srfi 路线,那么 srfi-28 形式化 format。 (是的,参考实现使用 srfi-6,但实现通常会使用它们拥有的任何内置函数——srfi-26 的 mzscheme 实现只使用它自己的format。)
    【解决方案5】:

    我认为这是一个简单的代码,可以满足您的需求。
    它不使用特定于实现的东西,而且非常简单。

    但是请注意,它不能正确处理字符串中的特殊字符(例如,“a\"b\"c" 将变为 "a"b"c")。

    (define join
        (lambda (l delim to-str)
          (fold-left
            (lambda (str elem)
              (string-append str delim (to-str elem)))
            (to-str (car l))
            (cdr l))))
    (define sexpr->string 
          (lambda (sexpr)
            (cond 
              ((number? sexpr) (number->string sexpr))
              ((symbol? sexpr) (symbol->string sexpr))
              ((boolean? sexpr) (if sexpr "#t" "#f"))
              ((string? sexpr) (string-append "\"" sexpr "\""))
              ((char? sexpr) (string-append "#\\" (string sexpr)))
              ((vector? sexpr) 
               (let ((s-vec (join (vector->list sexpr) " " sexpr->string)))
                 (string-append "#(" s-vec ")")))
              ((null? sexpr) "()")
              ((list? sexpr) (string-append "(" (join sexpr " " sexpr->string) ")"))
    
              ((pair? sexpr) 
               (let ((s-car (sexpr->string (car sexpr)))
                     (s-cdr (sexpr->string (cdr sexpr))))
                 (string-append "(" s-car " . " s-cdr ")"))))))
    

    【讨论】:

      【解决方案6】:

      如果您使用的是兼容 R6RS 的方案,则可以使用 write 函数与 call-with-string-output-port 结合使用。

      #!r6rs
      (import (rnrs base)
              (rnrs io ports)   ;for call-with-string-output-port
              (rnrs io simple)) ;for write
      
      ;; Produces a string representation of the S-Expression e
      (define (expr->string e)
        (call-with-string-output-port
         (lambda (out) (write e out))))
      

      一些例子:

      > (expr->string '(lambda (x) (+ x 1)))
      "(lambda (x) (+ x 1))"
      > (expr->string '(lambda (x) (string-append x " and cheese!")))
      "(lambda (x) (string-append x \" and cheese!\"))"
      

      顺便说一句,通常也可以使用readopen-string-input-port 结合使用。

      ;; Produces the S-Expression represented by the string.
      ;; In most cases this will be a left-inverse of expr->string,
      ;; so that (string->expr (expr->string e)) = e.
      ;; If the string has multiple S-Expressions represented
      ;; in it, this only returns the first one.
      (define (string->expr s)
        (read (open-string-input-port s)))
      

      一些例子:

      > (string->expr "(lambda (x) (+ x 1))")
      (lambda (x) (+ x 1))
      > (equal? (string->expr "(lambda (x) (+ x 1))")
                '(lambda (x) (+ x 1)))
      #t
      > (equal? (string->expr (expr->string '(lambda (x) (+ x 1))))
                '(lambda (x) (+ x 1)))
      #t
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-05
        相关资源
        最近更新 更多