Re: [racket-users] Problem with macro which implements selectors for mutable pairs

2016-05-12 Thread Jens Axel Søgaard
Hi Joan,

As Alex writes using define-macro is not recommended.
It can be used to write very simple macros, but if you try anything
complicated then you are likely to run into problems.

The best strategy is therefore to use define-syntax from the beginning.
The solution below has a lot in common with the solution from Alex,
but I have attempted to use syntax-parse only to pick out elements
from the input syntax.

There are two versions of the macro with-mcxrs/explicit and with-mcxr.
The first require the user to explicitly write which identifiers he needs.
My initial thought was to let with-mcxrs search for identifiers and then
expand into with-mcxrs/explicit. I decided to take another approach
and let the expander find the identifiers for me.

In racket applications like (mcar xs) expand into (#%app mcar xs).
If we rebind #%app we can make an application that treats
applications of the type (mxcr expr) differently from other applications.

If you need   mcar  to work as variable reference too, then that could
be added using a so-called set!-transformer.

Anyways, here is the code:

#lang racket
(require compatibility/mlist
 (for-syntax syntax/parse))

;;; Utilites used by the macros below.

(begin-for-syntax
  ; mcxr-string? : string -> boolean(ish)
  ;   is the string s of the form mcxr where
  ;   x is a sequence of a's and d's?
  (define (mcxr-string? s)
(regexp-match "^mc(a|d)*r$" s))

  ; mcxr-identifier? : syntax -> boolean
  ;   is stx an identifier whose name is of the form mcxr ?
  (define (mcxr-identifier? stx)
(and (identifier? stx)
 (mcxr-string? (symbol->string (syntax-e stx)

  ; mcxr-identifier->xs : identifier -> list-of-symbols
  ;   Given an identifier of the type mcxr:
  ;   returns a list of a's and d's matching the x
  ;  > (mcxr-identifier->xs #'mcaadar)
  ;  '(a d a a)
  ;   Note the order is reversed.
  (define (mcxr-identifier->xs id)
(define str   (symbol->string (syntax-e id)))
; remove mc and r from the start and end respectively
(define x-str (substring str 2 (- (string-length str) 1)))
(map (λ (c) (string->symbol (string c)))
 (reverse (string->list x-str)

; SYNTAX (mcxr (x ...) expr) where x is either a or d
;  Example:
; (mxcr (d d a) e)  expands to   (mcar (mcdr (mcdr e)))
; (mxcr mcaddr e)   expands to   (mxcr (d d a) e) which expands to (mcar
(mcdr (mcdr e)))
(define-syntax (mcxr stx)
  (define error-str (string-append "expected (mcxr (x ...) expr) or (mcxr
id expr) "
   "where  x  is  a or d "
   "and id is of the form mcxr"))
  (syntax-parse stx
#:datum-literals (a d)
[(_mcxr ()  expr)   #'expr]
[(_mcxr (a x ...) expr) #'(mcxr (x ...) (mcar expr))]
[(_mcxr (d x ...) expr) #'(mcxr (x ...) (mcdr expr))]
[(_mcxd idexpr) (if (mcxr-identifier? #'id)
(with-syntax ([(x ...) (mcxr-identifier->xs
#'id)])
  #'(mcxr (x ...) expr))
(raise-syntax-error 'mcxr error-str stx))]
[_ (raise-syntax-error 'mcxr error-str stx)]))

; SYNTAX (with-mcxrs/explicit-ids (id ...) body ...)
;   id is an identifier of the form mcxr
;   the given identifiers will be bound in body
;   to a function matching their name.
;   For example  mcadr will be bound to (lambda (v) (mcar (mcdr v))) in
body.
(define-syntax (with-mcxrs/explicit-ids stx)
  (syntax-parse stx
[(_ (id ...) body ...)
 (with-syntax ([(xs ...) (map mcxr-identifier->xs (syntax->list #'(id
...)))])
   #'(let ([id (lambda (v) (mcxr xs v))]
   ...)
   body ...))]))

(with-mcxrs/explicit-ids (mcaar mcdar mcaadr mcdadr)
  (let ((a (mcons (mcons 1 2) (mcons (mcons 3 4) '()
(list (mcaar a)
  (mcdar a)
  (mcaadr a)
  (mcdadr a


;;; The downside of the above macro is that the user of
with-mcxrs/explicit-ids
;;; needs to specify which functions he needs.
;;; If we assume that he only want's to apply  mcxr, then we can
;;; make a new version of application (#%app) that rewrites
;;; applications of the form (mcxr expr) but leaves other applications
;;; untouched.

(define-syntax (mcxr-app stx)
  (syntax-parse stx
[(_mcxr-app id expr)
 (cond
   [(mcxr-identifier? #'id)  #'(mcxr id expr)]
   [else #'(id expr)])]
[(_#%app expr arg ...)   #'(#%app expr arg ...)]))


;;; Given mcxr-app we can now write with-mcxrs like this,
;;; by locally rebinding #%app to mcxr-app in body.

(define-syntax (with-mcxrs stx)
  (syntax-parse stx
[(_ body ...)
 (with-syntax ([new-#%app (syntax-local-introduce
  (datum->syntax #'stx '#%app #'here))])
   #'(let-syntax ([new-#%app (make-rename-transformer #'mcxr-app)])
   body ...))]))

(with-mcxrs
(let ((a (mcons (mcons 1 2) (mcons (mcons 3 4) '()
  (list (mcaar a)
(mcdar a)
  

Re: [racket-users] Problem with macro which implements selectors for mutable pairs

2016-05-12 Thread Alex Knauth

> On May 12, 2016, at 4:45 AM, Joan Martin  wrote:
> 
> Hi, 
> I'm trying to program a macro which defines different selectors for mutable 
> pairs.
> I know in Racket it's possible to use only mcar and mcdr, but mcdar etc. 
> could be useful for me.
> 
> I would like to use macro this way: 
> 
> (with-mcxrs
>  (let ((a (mcons (mcons 1 2) (mcons (mcons 3 4) '()
>   (list (mcaar a)
> (mcdar a)
>(mcaadr a)
>(mcdadr a
> 
> Mcxrs will be defined in macro's body and then whole expresion would be 
> evaluated - now with bindings in macro's environment so no error should 
> appear.
> I think procedure seek and macro defines3 are ok (when using separately they 
> work fine) but in a macro "with-mcxrs" an error appears: mcaar undefined. 

There's a macro with a similar purpose in the implementation of the racket lens 
library, although instead of a `with-mcxrs` form, it was basically a 
`define-mcxrs` form, except it was for lenses instead of mutable pairs. The 
code is here if you're interested: 
https://github.com/jackfirth/lens/blob/master/lens/private/list/cadr-etc.rkt

Because it behaves like a `define-mcxrs` form, it can only define a fixed 
number of `cadr`-like functions, but there are a fixed number of existing 
`cadr`-like functions anyway.

> Where's the problem? I can't figure it out. I would be glad if anyone could 
> give me some advice. 

I noticed you're using `define-macro` for both `with-mcxrs` and `defines3`, and 
you're generating lists using `quasiquote`. But in racket there are much better 
ways of doing things.

For one thing, if you use `quasiquote`, you don't get any control over 
bindings, and without that, the bindings you're introducing aren't visible to 
the macro user, because it's in the wrong lexical scope. To fix that, you can 
use a form like `define-syntax`, with a pattern matching tool like 
`syntax-case` or `syntax-parse`. 

For that I would strongly recommend Greg Hendershott's Fear of Macros tutorial:
http://www.greghendershott.com/fear-of-macros/

But if you don't have time to read that right now, here's how I would define it 
that way.

Instead of symbols and lists, `define-syntax` macros use syntax objects, which 
are just a thin wrapper around them containing source location and lexical 
scoping information. Instead of quote, there's syntax. Instead of quasiquote, 
unquote, and unquote-splicing, there's quasisyntax, unsyntax, and 
unsyntax-splicing. Instead of ', `, ,, and ,@, the abbreviations are #' for 
syntax, #` for quasisyntax, #, for unsyntax, and #,@ for unsyntax-splicing. 
There's also stx-car, stx-cdr, stx-map, etc.

Also, an identifier is just a syntax value that wraps a symbol.

First, I would define some helper functions for taking an mcxr identifier and 
getting an implementation for it:

(begin-for-syntax
  ;; mcxr->mcxr-implementation : Identifier -> Syntax
  (define (mcxr->mcxr-implementation id)
(define str (symbol->string (syntax->datum id)))
(define x-list (string->list (substring str 2 (sub1 (string-length str)
(x-list->mcxr-implementation x-list))
  ;; x-list->mcxr-implementation : (Listof Char) -> Syntax
  (define (x-list->mcxr-implementation x-list)
#`(compose
   #,@(map x-char->mcxr-id x-list)))
  ;; x-char->mcxr-id : Char -> Identifier
  (define (x-char->mcxr-id char)
(cond [(char=? char #\a) #'mcar]
  [(char=? char #\d) #'mcdr]
  [else (error "expected the character 'a' or 'd', got ~v" char)]))
  )

The macro also has to find all of the mcxr-like identifiers in the body, so I 
would also define helper functions for that:

(require (for-syntax syntax/parse))

(begin-for-syntax
  ;; mcxr-id? : Identifier -> Boolean
  ;; returns true if the identifier matches the form mc[ad]*r
  (define (mcxr-id? id)
(mcxr-string? (symbol->string (syntax->datum id
  ;; mcxr-string? : String -> Boolean
  (define (mcxr-string? str)
(regexp-match? #rx"^mc[a|d]*r$" str))
  ;; find-mcxr-ids : Any (Listof Identifier) -> (Listof Identifier)
  ;; the ids argument is an accumulator for the ids found so far
  (define (find-mcxr-ids stx ids)
(syntax-parse stx
  [mcxr:id #:when (mcxr-id? #'mcxr) (cons #'mcxr ids)]
  [(a . b) (find-mcxr-ids #'a (find-mcxr-ids #'b ids))]
  [else ids]))
  )

And finally, the macro:

(require (for-syntax racket/list syntax/stx))

(define-syntax with-mcxrs
  (lambda (stx)
(syntax-parse stx
  [(_ . body)
   #:with [mcxr-id ...] (remove-duplicates (find-mcxr-ids #'body (list)) 
bound-identifier=?)
   #:with [mcxr-impl ...] (stx-map mcxr->mcxr-implementation #'[mcxr-id 
...])
   #'(let ([mcxr-id mcxr-impl] ...) . body)])))

If you read Fear of Macros, this `#:with` stuff is similar to using the 
`with-syntax` form.

Trying it out with your example:

> (with-mcxrs
   (let ([a (mcons (mcons 1 2) (mcons (mcons 3 4) '()))])
 (list (mcaar a)
   (mcdar a)
   (mcaadr a)
   (mcdadr 

[racket-users] Problem with macro which implements selectors for mutable pairs

2016-05-12 Thread Joan Martin
Hi, 
I'm trying to program a macro which defines different selectors for mutable 
pairs.
I know in Racket it's possible to use only mcar and mcdr, but mcdar etc. could 
be useful for me.

I would like to use macro this way: 

(with-mcxrs
  (let ((a (mcons (mcons 1 2) (mcons (mcons 3 4) '()
   (list (mcaar a)
 (mcdar a)
 (mcaadr a)
 (mcdadr a

Mcxrs will be defined in macro's body and then whole expresion would be 
evaluated - now with bindings in macro's environment so no error should appear.
I think procedure seek and macro defines3 are ok (when using separately they 
work fine) but in a macro "with-mcxrs" an error appears: mcaar undefined. 
Where's the problem? I can't figure it out. I would be glad if anyone could 
give me some advice. 

And could "defines3" be out of macro "with-mcxrs"? Or should it be inside - 
like in my code? 
Thanks a lot.

Code:
 first I go though whole body and I store found mcxrs in list, which is called 
"selectors" in let loop. And then call another macro "defines3" which should 
return procedure - for example: (lambda (pair) (mcar (mcdr (mcar pair. And 
this procedure should be defined as a value of particular mcaar or mcdar etc.

(define-macro with-mcxrs
  (lambda body

`(define-macro defines3 
  (lambda (chars)
(let ((loop (gensym)))
  `(lambda (pair)
 (let ,loop ((chsez ,chars))
   (if (null? chsez)
   pair
   (if (equal? (car chsez) #\a)
   (mcar (,loop (cdr chsez)))
   (mcdr (,loop (cdr chsez ))

(define seek2   
  (let ((pom '() ))
(lambda (l)
  (cond ((null? l) pom )
((list? (car l)) (begin(seek2 (car l))
   (seek2 (cdr l))) )
(else
 (if (not (symbol? (car l)))
 (seek2 (cdr l))
 (let* ((test (symbol->string(car l)))
(len (string-length test)))
   (if (> len 4)
   (if (or (equal? (substring test 0 3) "mca")
   (equal? (substring test 0 3) "mcd"))
   (begin 
 (set! pom (cons (car l) pom) )
 (seek2 (cdr l)))
   (seek2 (cdr l)))
   (seek2 (cdr l)) 

(let ((loop (gensym)))
  `(let ,loop ((selectors (,seek2 (quote ,@body)) )) ;;list of selectors
(cond ((null? selectors) (,@body))
  (else
(define (car selectors)
 (defines3 (string->list
(substring (car l) 2
(- (string-length (car l))1)) )))
   (,loop (cdr selectors))) )))  ))


-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.