[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Scheme-reports] Formal Response #382: Allow "if" to accept arbitrarily many if-then pairs



> This seems unrelated to the original topic

Well, you said yourself: "This is somewhat off-topic for the formal comment, but it's quite easy to do this in Racket:".  I suppose my original wording was perhaps unnecessarily provocative and lending itself to an offtopic discussion.  The fundamental problem with Racket (for what I want to do) is the phase separation.  It manifested itself first as "When I redefined if, it wasn't usable for other macro definitions", so I mentioned it, in my response to "It is trivial to redefine if".

As you show, it is possible to define "if" to be used at compile-time, but this is not satisfactory because the macros I proceed to define, using if, will not be usable at compile-time to define a third set of macros.  I could (for-syntax <define the second set of macros>), which would make them available at compile-time, but that would not succeed because "if" does not have the right definition at phase 2 (used when defining macros for compile-time).  This could be fixed by (for-syntax (for-syntax <define if the way I want>)).  However, if I wanted to define more macros that depended on the third set, I would need to (for-syntax (for-syntax <define second set of macros>)), and (for-syntax (for-syntax (for-syntax <define if>))).  And so on.  I considered some schemes like defining a "define-macro" procedure that would write all previous definitions to a file and require it (for-syntax), but decided this was getting ridiculous--these are the insane workarounds I mentioned.

The "meh" macro was just a test case to illustrate the problem.  As I've said, I want to define a bunch of macros, any of which might be defined in terms of previous macros--and functions, though macros is already hard enough.  My intent is to port as many as possible of the various convenience macros from Arc to whatever Lisp I'm currently using, and to do it as conveniently as possible.  The ideal test case defines the macro-defining macro "mac" (equivalent to defmacro), uses it to define the function-defining macro "def", uses "def" to define list-manipulating functions like "tuples", uses "mac" to define the macro "if" somewhere along the way (possibly using "tuples"), uses "mac" and "if" to define the gensym-binding macro "w/uniq", uses "mac" and "if" and "w/uniq" to define the destructuring binding macro "let", uses "mac" and "if" and "let" to define the binding macro "with", ...

I've done much of the above in Common Lisp, though the depth of the dependency tree is slightly less than all that.  (I got stuck at redefining built-in operators, though now that Cowan's 'shadow trick seems to work, I may extend it further.)  If you are curious: http://paste.lisp.org/display/132522

--John Boyle
Science is what we understand well enough to explain to a computer. Art is everything else we do. --Knuth



On Thu, Oct 11, 2012 at 7:17 PM, Sam TH <sam@x> wrote:
On Thu, Oct 11, 2012 at 10:11 PM, John Boyle <johnthescavenger@x> wrote:
> The difficulty is using the newly defined "if" in the definition of
> low-level macros, or otherwise at compile-time.  This seems to be due to
> Racket's phase separation.  Is there a way to turn that off?
>
> #lang racket
>
>
> (require syntax/parse/define)
> (define-simple-macro (if (~seq test result) ... final)
>   (cond [test result] ... [else final]))
>
> (if (even? 7) "seven" (odd? 8) "eight" "neither")
>
> (require mzlib/defmacro)
>
> (defmacro meh (x)
>   (if (> x 5)
>       1
>       (> x 2)
>       2
>       3))
>
> Running this in DrRacket produces:
>
> if: bad syntax;
>  has 5 parts after keyword in: (if (> x 5) 1 (> x 2) 2 3)
>
> The same happens if you put (begin-for-syntax (if #f 1 #f 2 3)) or
> (define-for-syntax n (if #f 1 #f 2 #f 3)) after your supplied definition.
> (For those not familiar, the "-for-syntax" forms in Racket execute things at
> compile-time, or I believe "phase 1" rather than "phase 0".)  However, it
> works to use "if" with three arguments there: it is using the built-in
> definition of "if", which appears to be present at all of Racket's
> compilation phases by default.

Right, phases are a fundamental part of Racket.

> What I want is the intermixing of runtime and compilation time that the
> phase separation seems determined to prevent (e.g. define a macro, use that
> macro in the definition--not expansion--of another macro, use that macro in
> the definition of another macro, and so on).  I tried this a long time ago
> and became convinced it was impossible without insane workarounds.

This seems unrelated to the original topic, which is the redefinition
of built-in forms.

However, there are many ways to achieve what you want in Racket
without losing the advantages of phases.

Here's one:

#lang racket
(require (for-syntax mzlib/defmacro))

(begin-for-syntax
  (require syntax/parse/define)
  (define-simple-macro (if (~seq test result) ... final)
    (cond [test result] ... [else final])))

(defmacro meh (x)
  (if (> x 5)
      1
      (> x 2)
      2
      3))

And here's another:

#lang racket

(module m racket
  (provide if)
  (require syntax/parse/define)
  (define-simple-macro (if (~seq test result) ... final)
    (cond [test result] ... [else final])))

(require 'm mzlib/defmacro (for-syntax 'm))

(defmacro meh (x)
  (if (> x 5)
      1
      (> x 2)
      2
      3))

(define (meh2 x)
  (if (> x 5)
      1
      (> x 2)
      2
      3))


>
>
> On Thu, Oct 11, 2012 at 6:54 PM, Sam Tobin-Hochstadt <samth@x>
> wrote:
>>
>> On Thu, Oct 11, 2012 at 9:29 PM, John Boyle <johnthescavenger@x>
>> wrote:
>> > While all Schemes I've tested that support define-syntax do allow
>> > redefinition of "if"... on Racket, it does not play well with low-level
>> > macros (using datum->syntax, or the "mzlib/defmacro" library) due to
>> > their
>> > phase-separation.
>>
>> This is somewhat off-topic for the formal comment, but it's quite easy
>> to do this in Racket:
>>
>> #lang racket ;; https://gist.github.com/3876906
>>
>> (require syntax/parse/define)
>> (define-simple-macro (if (~seq test result) ... final)
>>   (cond [test result] ... [else final]))
>>
>> (if (even? 7) "seven" (odd? 8) "eight" "neither")
>>
>> I'm not sure what difficulty you ran into, but it shouldn't be
>> necessary to use `datum->syntax`, `defmacro`, or any other low-level
>> features.
>> --
>> sam th
>> samth@x
>
>



--
sam th
samth@x

_______________________________________________
Scheme-reports mailing list
Scheme-reports@x
http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports