[racket] a little macro exercise
Ah, yes, I didn't see Carl's solution, which is pleasantly concise and particularly nice because of the single case. But I still think the point about fall-through is important to the performance model of `switch' -- it's what Duff's Device relies on, for example.
If you care about constructs like `switch', of course. ;)
Dave
On Oct 9, 2010, at 4:50 PM, Jay McCarthy wrote:
> This looks a lot like Carl's (and my modification of it.)
>
> Jay
>
> On Sat, Oct 9, 2010 at 5:46 PM, David Herman <dherman at ccs.neu.edu> wrote:
>> I thought about the "am I falling through?" approach you've been taking, but the problem is that it keeps having to recompute the same test. In C-like languages, one of the benefits of `switch' [1] is that fall-through is expected to either be a literal "execute the next instruction in the PC" or at least a jump to a fixed address. So I prefer an approach that sets up a basic-block-like structure, like so:
>>
>> +-------+
>> | test1 |
>> +-------+ ....> +------+
>> . | rhs1 |
>> . +------+
>> v .
>> +-------+ .
>> | test2 | v
>> +-------+ ....> +------+
>> . | rhs2 |
>> . +------+
>> v .
>> +-------+ .
>> | test3 | v
>> +-------+ ....> +------+
>> . | rhs3 |
>> . +------+
>> . .
>> . .
>>
>> If each of these blocks is compiled as a local thunk, I'd expect a decent (not necessarily brilliant) Scheme compiler to be able to turn the function call at the end of each rhs_i block into a jump to a static address, and possibly even reorder the basic blocks to make some of them jump-less. With modern branch-prediction, the latter may be unnecessary.
>>
>> With that, here's my solution:
>>
>> #lang racket
>>
>> (require racket/stxparam)
>>
>> (define-syntax-parameter break
>> (lambda (stx)
>> (raise-syntax-error 'break "used outside of cas-cad-e case" stx)))
>>
>> (define-syntax (cas-cad-e stx)
>> (syntax-case stx ()
>> [(_ disc)
>> #'(void)]
>> [(_ disc [lhs rhs ...] ... [last-lhs last-rhs ...])
>> (let ([test-ids (generate-temporaries (syntax->list #'(lhs ...)))]
>> [consequent-ids (generate-temporaries (syntax->list #'(lhs ...)))]
>> [last-test-id (car (generate-temporaries (list #'last-lhs)))]
>> [last-consequent-id (car (generate-temporaries (list #'last-lhs)))])
>> (with-syntax ([(test ...) test-ids]
>> [(consequent ...) consequent-ids]
>> [last-test last-test-id]
>> [last-consequent last-consequent-id])
>> (with-syntax ([(next-test ...) (append (cdr test-ids) (list last-test-id))]
>> [(next-consequent ...) (append (cdr consequent-ids) (list last-consequent-id))])
>> (with-syntax ([test0 (if (null? test-ids) last-test-id (car test-ids))])
>> #'(let ([disc-v disc])
>> (let/ec k
>> (syntax-parameterize ([break (syntax-rules ()
>> [(_ v)
>> (k v)])])
>> (define (test)
>> (case disc-v
>> [lhs (consequent)]
>> [else (next-test)]))
>> ...
>> (define (consequent)
>> rhs ...
>> (next-consequent))
>> ...
>> (define (last-test)
>> (case disc-v
>> [last-lhs (last-consequent)]))
>> (define (last-consequent)
>> last-rhs ...)
>> (test0))))))))]))
>>
>> Dave
>>
>> [1] Please do not construe this as tacit approval of the `switch' form. Ick.
>>
>> On Oct 9, 2010, at 6:13 AM, Jay McCarthy wrote:
>>
>>> I don't really like have the call-with-values and apply there, so
>>> here's another version. It makes the macro a bit longer with the
>>> additional case and has the pattern duplicated once, but it seems
>>> worth it:
>>>
>>> (define-syntax cas-cad-e
>>> (syntax-rules ()
>>> [(_ e) (begin e (void))]
>>> [(_ e [(n ...) code ...] ... [(n_l ...) code_l ...])
>>> (let/ec esc
>>> (syntax-parameterize
>>> ([break (make-rename-transformer #'esc)])
>>> (let* ([tmp e]
>>> [earlier? #f]
>>> [earlier?
>>> (if (or earlier? (equal? tmp n) ...)
>>> (begin code ... #t)
>>> earlier?)]
>>> ...)
>>> (when (or earlier? (equal? tmp n_l) ...)
>>> code_l ...))))]))
>>>
>>> Regarding Shriram's bug. The only thing that occurs to me is that
>>> you'd want eqv? and a ' on the ns, to be more like case.
>>>
>>> Jay
>>>
>>> On Fri, Oct 8, 2010 at 10:39 PM, Jay McCarthy <jay.mccarthy at gmail.com> wrote:
>>>> You got me
>>>>
>>>> Sent from my iPhone
>>>>
>>>> On Oct 8, 2010, at 10:33 PM, Eli Barzilay <eli at barzilay.org> wrote:
>>>>
>>>>> 8 minutes ago, Jay McCarthy wrote:
>>>>>> Alright, here's the version with no mutation:
>>>>>
>>>>> (cas-cad-e 1 [(1) (values 1 2 3)])
>>>>>
>>>>> In other words:
>>>>>
>>>>> (define-syntax-rule (cas-cad-e e [(n ...) code ...] ...)
>>>>> (let/ec esc
>>>>> (syntax-parameterize ([break (make-rename-transformer #'esc)])
>>>>> (let*-values ([(tmp) e]
>>>>> [(earlier? ret) (values #f (void))]
>>>>> [(earlier? ret)
>>>>> (if (or earlier? (equal? tmp n) ...)
>>>>> (values #t (call-with-values (lambda () code ...) list))
>>>>> (values earlier? ret))]
>>>>> ...)
>>>>> (apply values ret)))))
>>>>>
>>>>> --
>>>>> ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
>>>>> http://barzilay.org/ Maze is Life!
>>>>
>>>
>>>
>>>
>>> --
>>> Jay McCarthy <jay at cs.byu.edu>
>>> Assistant Professor / Brigham Young University
>>> http://teammccarthy.org/jay
>>>
>>> "The glory of God is Intelligence" - D&C 93
>>> _________________________________________________
>>> For list-related administrative tasks:
>>> http://lists.racket-lang.org/listinfo/users
>>
>>
>
>
>
> --
> Jay McCarthy <jay at cs.byu.edu>
> Assistant Professor / Brigham Young University
> http://teammccarthy.org/jay
>
> "The glory of God is Intelligence" - D&C 93