开发者

Converting a Scheme expression to a string

Given an expression '(lambda (x) x) How can I translate this into a string. I thought symbol->string will do the job but no it cant not a sy开发者_开发百科mbol.

e.g for a macro to-string: (to-string (lambda(x) x)) this should return >> "(lambda (x) x)"

Any ideas folks Thanks


Standard Scheme (at least in the R5RS sense) has no way of doing this, so if you want portable code, you need to walk the structure yourself. Tedious, but not too complicated (even for dotted lists). But if you just want some working version, then you should look in your implementation's manual and search for the way to do this. The answer will almost always be simple, for example, in PLT Scheme you'd use (format "~s" '(lambda ...))


The expression '(lambda (x) x) is a quoted list.

The expression (lambda (x) x) is some kind of compiled, opaque, executable, internal object of the runtime.

symbol->string simply converts a symbol to a string, which is a sequence of characters.

If you're working with a list, you can simply walk the list and print the individual components out. In fact (write '(lambda (x) x)) will simply print the list out.

Many schemes have something akin to (with-output-to-string ... ) that returns a string of all the output written to the standard port.

However, if you do (write (lambda (x) x)), you'll get who knows what. You'll get whatever the implementation provides when dumping an executable function type. Some may print a "disassembly" showing the source code. Others may simply print #function or something equally useless.

In short, if you just want to print out a list, there are all sorts of mechanisms for that.

If you want to print out the source code of a compiled function, that's a completely different problem, very implementation dependent, and may well be impossible.


Use pretty-format:

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


You should walk through the conses. When a new cons starts write "(", when it ends write ")" and use symbol->string for symbols inside the conses.

You can extend this with type dispatching. May be pretty print exists in scheme too?


This is a simple code that, I think, does what you want.
It uses no implementation specific stuff and is quite straight forward.

Note, however, that it doesn't correctly handle special characters in strings (e.g. "a\"b\"c" will turn to "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 ")"))))))


If you are using an R6RS-compatible scheme, you can use the write function combined with 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))))

Some examples:

> (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!\"))"

By the way, it's usually possible to go in the other direction as well, using read combined with open-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)))

Some examples:

> (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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜