Multiple lines comments in Scheme (RnRS)
Asked Answered
P

2

5

I created this solution:

; use like this:
; (/* content ... */ <default-return>)
; or
; (/* content ... */) => #f
(define-syntax /*
  (syntax-rules (*/)
    ((/* body ... */) #f)
    ((/* body ... */ r) r)))

But is it really the best or easiest way?

Poulson answered 17/9, 2010 at 1:51 Comment(0)
S
8

You can't do it this way -- it won't work for a number of contexts. Here are some examples that won't work:

(+ (/* foo */) 1 2)

(define (foo a (/* b */) c) ...)

(/* foo; bar */)

(/*x*/)

(let ((x (/* 1 */) 2))
  ...)

(let ((/* (x 1) */)
      (x 2))
  ...)

(car '((/* foo */) 1 2 3))

There is no standard multi-line comment in the Scheme reports up to R5RS, but R6RS has added a syntax that was widely used anyway: #|...|#.

But if you really want to...

Here's what I was talking about in the comment: if you're willing to wrap the whole code in a macro, then the macro can process the whole body, which can be effective in many more contexts. Pretty much all of them except for trying to comment out syntactically invalid stuffs like the semicolon example above, or an unterminated string. You can judge for yourself whether it's really worth the effort...

(Personally, as much as I enjoy such games, I still think they're pointless. But if you really enjoy these games and you think they're useful, then see the homework section below...)

(define-syntax prog (syntax-rules () [(_ x ...) (prog~ (begin x ...))]))
(define-syntax prog~
  (syntax-rules (/* */)
    [(prog~ (/* x ...) b ...)
     ;; comment start => mark it (possibly nested on top of a previous mark)
     (prog~ (x ...) /* b ...)]
    [(prog~ (*/ x ...) /* b ...)
     ;; finished eliminating a comment => continue
     (prog~ (x ...) b ...)]
    [(prog~ (*/ x ...) b ...)
     ;; a comment terminator without a marker => error
     (unexpected-comment-closing)]
    [(prog~ (x0 x ...) /* b ...)
     ;; some expression inside a comment => throw it out
     (prog~ (x ...) /* b ...)]
    [(prog~ ((y . ys) x ...) b ...)
     ;; nested expression start => save the context
     (prog~ (y . ys) prog~ ((x ...) (b ...)))]
    [(prog~ (x0 x ...) b ...)
     ;; atomic element => add it to the body
     (prog~ (x ...) b ... x0)]
    [(prog~ () prog~ ((x ...) (b ...)) nested ...)
     ;; nested expression done => restore context
     (prog~ (x ...) b ... (nested ...))]
    [(prog~ () /* b ...)
     ;; input done with an active marker => error
     (unterminated-comment-error)]
    [(prog~ () b ...)
     ;; all done, no markers, not nested => time for the burp.
     (b ...)]))

And an example:

(prog

 (define x 1)

 (display (+ x 2)) (newline)

 /*
 (display (+ x 10))
 /* nested comment! */
 (/ 5 0)
 */

 (define (show label /* a label to show in the output, before x */
               x /* display this (and a newline), then returns it */)
   (display label)
   (display x)
   (newline)
   x
   /* this comment doesn't prevent the function from returning x */)

 (let ([x 1] /* some comment here */ [y 2])
   (show "result = " /* now display the result of show... */
         (show "list = " (list x /* blah blah */ y)))
   'done /* just a value to return from the `let' expression */)

 (show "and ... " '(even works /* boo! */ inside a quote))

 )

Homework

For extra credit, extend it so you can comment out unbalanced parens. For example, make this work:

(prog
 blah blah /* junk ( junk */ blah blah /* junk ) junk */ blah blah.
 )

Obviously, the input as a whole should have balanced parens -- this means that there's not much point in implementing this kind of an extension. Even without it, what's the point in commenting out an unbalanced paren?

But if anyone got all the way here, then you must enjoy this kind of self-torture ... right?

Sideswipe answered 17/9, 2010 at 2:11 Comment(18)
Thanks so much! So, my code could be useful for < R5RS. But please, give me real examples when this will not work fine. --- And, for R5RS, if this code is not good enough, could you try to give me a better?Poulson
(cons '(/*I'm quoting this/*)a foo)Pentyl
Please, give me the original cons construction and what you would like to comment. Sorry, but your code example didn't make sense for me.Poulson
if the original was (cons 'a foo), I think you could do it: (cons (/* 'a */ 'temp-value) foo) if you want to comment 'aPoulson
and as arguments of a function: (sum a b c d (/* e */ 0) f g h)Poulson
Yes, that's one case -- I added some more examples.Sideswipe
But you are using in the wrong way! :) The default is return #f but you can define another value. E.g.: use (+ (/* foo / 0) 1 2) instead only (+ (/ foo */) 1 2). And you didn't give me a good solution for <= R5RS. I am waiting, thanks!Poulson
(1) Sure you can change it to 0 -- but there is no way to know in advance which value you need; (2) even if you do have some magical value, it won't work in a call to list -- which will inevitably get to have one extra value; (3) I can't give you a solution for R5RS and below -- what I said is that there isn't one; (4) I also said that for all practical purposes, this is not a problem since the #|...|# syntax was adopted by almost all (R5RS) implementations; (5) if you're looking for a way to write portable R5RS code, then you'd have much bigger problems.Sideswipe
I forgot: (2.5) using it in a function application was just one example out of many where this didn't work.Sideswipe
Ok Eli. I didn't fully agree, but I understand your POV. My code proposal was just to supply a limitation and it is very useful in the most cases. I just asked if somebody has something better, but nobody answer until now.Poulson
SpamKids: There is nothing to agree or disagree on -- your form works only in a limited context where an expression is expected and what it evaluates to is discarded. That leaves a whole bunch of contexts where it doesn't work as a multiline comment.Sideswipe
I agree with that, but my question is still open. I asked: is it the best way? (I didn't ask "it works for all cases?"). I'm sorry but "it didn't work" is not a useful answer in this case.Poulson
It's "the best" under a specific definition of the word. IMO, a far better solution (which I mentioned a few times) is to use #|...|# which all serious Scheme implementations support, and is part of R6RS. But this is a solution to the practical problem of multi-line comments -- if you're just trying to play with macros than it's irrelevant. As for "it didn't work" -- well, you posted code, and I pointed at how it doesn't work -- is there anything else I can say? Does "it worked for some limited value of \"worked\"" work out better?Sideswipe
One more note: it could be made better, and handle more cases if you're willing to wrap the whole code inside some macro, this macro can then do a "code walk" and scan its whole contents, removing occurrences of /* ... */ (even without parens). But since you're confining yourself to R5RS, then you only have syntax-rules and the whole thing becomes way more difficult. Doable, but difficult.Sideswipe
Thanks and congrats! :) Now your answer make some sense! Very interesting!! Now I can mark as an acceptable answer. I think this kind of what-you-call "game" for me is not a game and is not useless. This is a elegant way to show how Scheme is flexible and multi-paradigm. Anyway, I don't have time for homework now, but I appreciate your initiative! Let it for the students, who knows they can give you a good solution? See you!Poulson
(sigh) It makes sense only in providing a less limited solution to a non-existent problem... It's an even worse solution if you consider it from a practicality point of view. It's known that the Scheme macro system can do such things, but it's known that it's very inconvenient -- so in terms of language design, forcing me to use an awkward construct instead of code is far from something I'd label as "elegant", "flexible", or "multi-paradigm".Sideswipe
Come on! You are trying to be more real than the king. It is a real problem in R5RS. I am talking about the book standard, not about inventions or specific implementations. And, yes, it shows the power of the language, even it is not really elegant - in this point I agree! I didn't have time to see carefully your answer, but I'll very soon. I'm curious to know how it works. See you!Poulson
@SpamKids: I did mention that if you care about the standard -- then the #|...|# was made official in R6RS, and that even more than that: it's a feature that is widely accepted, and I don't remember even one occasion where it was debated. So for all practical -- real -- standard -- purposes, you can rely on this feature to exist. Otherwise, submit a bug report. As for how it works -- it's not really complicated, just very verbose and very hard to follow -- because instead of real code, it does the transformations by rewrite rules.Sideswipe
P
6

MIT, Gnu, R6RS and R7RS support multi-line comments like this:

#|
    This is a comment
 |#
Plebeian answered 18/5, 2017 at 21:29 Comment(1)
.... and Chez 9.5 does as well (TIL: Chez supports it because Chez is a superset of R6RS)Aneroidograph

© 2022 - 2024 — McMap. All rights reserved.