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?

Felipe
  • 16,649
  • 11
  • 68
  • 92

2 Answers2

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?

Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • 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? – Felipe Sep 17 '10 at 02:16
  • `(cons '(/*I'm quoting this/*)a foo)` – Chuck Sep 17 '10 at 02:20
  • 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. – Felipe Sep 17 '10 at 02:27
  • if the original was (cons 'a foo), I think you could do it: (cons (/* 'a */ 'temp-value) foo) if you want to comment 'a – Felipe Sep 17 '10 at 02:30
  • and as arguments of a function: (sum a b c d (/* e */ 0) f g h) – Felipe Sep 17 '10 at 02:31
  • Yes, that's one case -- I added some more examples. – Eli Barzilay Sep 17 '10 at 14:25
  • 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! – Felipe Sep 17 '10 at 17:19
  • (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. – Eli Barzilay Sep 17 '10 at 23:35
  • I forgot: (2.5) using it in a function application was just *one* example out of many where this didn't work. – Eli Barzilay Sep 18 '10 at 00:31
  • 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. – Felipe Sep 20 '10 at 13:47
  • 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. – Eli Barzilay Sep 20 '10 at 16:33
  • 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. – Felipe Sep 20 '10 at 17:28
  • 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? – Eli Barzilay Sep 21 '10 at 01:49
  • 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. – Eli Barzilay Sep 21 '10 at 01:52
  • 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! – Felipe Sep 21 '10 at 05:29
  • 2
    (*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". – Eli Barzilay Sep 21 '10 at 12:46
  • 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! – Felipe Sep 21 '10 at 14:03
  • @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. – Eli Barzilay Sep 22 '10 at 05:26
6

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

#|
    This is a comment
 |#
David Jeske
  • 2,306
  • 24
  • 29