Question about macro (corrected)

132 views
Skip to first unread message

racke...@hotmail.com

unread,
Feb 4, 2012, 7:34:56 PM2/4/12
to Qilang
In trying to understand Shen macro system, I wanted to write a macro
that would translate every form of shape (c(a|d)+r xs), where c(a|d)+r
is a regular expression matching car, cdr, caar, cadr, ... etc, into
the corresponding composition of head and tail.

For example, macro should take (caadr [1 2 3 4 5]) and transform that
to
(head (head (tail [1 2 3 4 5]))).

As a first step in my experiment I wrote this:

(defmacro mymacro
[X Y] -> (if (= X car)
[head Y]
wrong))

But now, if I try

(car [3 4 5])

I get wrong as the answer (instead of 3).
The question is why?

Mark Tarver

unread,
Feb 5, 2012, 8:14:09 AM2/5/12
to Qilang
Well your macro will actually rewrite any 1-place application as
'wrong' if it is not (car X). I might expect that it would process
(car [1 2 3]), but I cannot tell for certain because the macro
disables the trace package: (track mymacro) returns 'wrong'!

On Feb 5, 12:34 am, "racketn...@hotmail.com" <racketn...@hotmail.com>
wrote:

vasil

unread,
Feb 5, 2012, 8:44:12 AM2/5/12
to qil...@googlegroups.com
Here is right definition:

(defmacro mymacro
[X Y] <- (if (= X car) [head Y] (fail)))

(13-) (defmacro mymacro
[X Y] <- (if (= X car) [head Y] (fail)))
macro

mymacro

(14-) (car [3 4 5])
3

(15-)

Explanation:
1. Macros are applied to AST untill the fix point of the transformation
is reached.
2. Your macro do next thing: if it gets expression (A B) it translates
this expression to either (head B) or symbol wrong.
3. Steps of macro expansion for (car [1 2 3]):
input AST resulting AST working macro comment

a. (car [1 2 3) (head [1 2 3]) mymacro AST was changed, so
macro expander makes next iteration
b (head [1 2 3]) wrong mymacro AST was changed,
macro expander makes next itaration
c wrong wrong - -

So, your macro will be applied twice to expression (car X) and finally
you'll get symbol wrong.

Right way to write macro is to leave AST unchanged, if macro should not
be applied.

As variant:

(defmacro mymacro
[car Y] -> [head Y])

Or whole macro for c[ad]*r:

(defcc <expr> -*- := -*-;)
(defcc <a-d-to-head-tail>
"a" <a-d-to-head-tail> := [head <a-d-to-head-tail>];
"d" <a-d-to-head-tail> := [tail <a-d-to-head-tail>];
"r" <expr> := <expr>;)
(defcc <cxr?>
"c" "a" <a-d-to-head-tail> := [head <a-d-to-head-tail>];
"c" "d" <a-d-to-head-tail> := [tail <a-d-to-head-tail>];)
(define cxr?
Sym Expr <- (compile (function <cxr?>) (append (explode (str Sym))
[Expr]))
_ _ -> (fail))
(defmacro mymacro
[X Y] <- (cxr? X Y))

(20-) (caddddddddddddddddr [1 2 2 2 2 2 2 2 2 2 2 2 3 3 4 4 45 5 4 54
56 45 3 64 563 45 63])
45


05.02.2012 03:34, racke...@hotmail.com пишет:

racke...@hotmail.com

unread,
Feb 5, 2012, 10:07:14 AM2/5/12
to Qilang
Oh thank you, Vasil! I didn't notice your post. I will study your
code. But, I would like to ask you: is my code ok?

Best regards,
racket noob
> 05.02.2012 03:34, racketn...@hotmail.com пишет:

racke...@hotmail.com

unread,
Feb 5, 2012, 10:03:32 AM2/5/12
to Qilang

I managed to do what I wanted. Here's the code:

(define str->symlist
  "" -> []
  X -> [(intern (pos X 0)) | (str->symlist (tlstr X))])

(define cxr?
  [c X Y | XS] -> (xr? [X Y | XS])
  _ -> false)

(define xr?
  [] -> false
  [X] -> (= X r)
  [X|XS] -> (and (or (= X a) (= X d)) (xr? XS)))

(define helper
  [a r] X -> [head X]
  [d r] X -> [tail X]
  [a L M | LS] X -> [head (helper [L M | LS] X)]
  [d L M | LS] X -> [tail (helper [L M | LS] X)])

(defmacro cxr-macro
  [X Y] -> (let CXR (str->symlist (str X))
              (if (cxr? CXR)
                  (helper (tail CXR) Y)
                  [X Y])))

Now, when i try (caadadr [1 [2 [3 4]] 5 6]), i get 3, just as it shoud
be.
I think this kind of macro is not possible to make in Common Lisp or
Scheme.

Mr. Tarver, I would like to thank you for this wonderful programming
language you have created!

vasil

unread,
Feb 5, 2012, 11:06:44 AM2/5/12
to qil...@googlegroups.com
> Oh thank you, Vasil! I didn't notice your post. I will study your
> code. But, I would like to ask you: is my code ok?

Yes, your code is fully functional and ok.

Martial Boniou

unread,
Feb 6, 2012, 9:07:29 AM2/6/12
to qil...@googlegroups.com
Very elegant solution, Vasil! It inspires me another version I quickly code this morning mixing Shen-Yacc and Prolog as a demo. It generates the typed functions CxxxR according to a fixed level using metaprogramming capability of Shen.

https://gist.github.com/1752144

Critics are welcomed. To sum up; I generate a tuple containing two lists: one for CARs, one for CDRs using combinations found by a prolog.

(0-) (build-fun-template 2)
=> (@p [car cadr caar] [cdr cddr cdar])

Then I eval a definition for each symbol-function in those lists. They are separated because of the different types to declare.

(1-) (build-cxrs 4)
(1-) (tc+)
(2-) (cddddr [1 2 3 4 5 6 7])
[5 6 7] : (list number)

Racket noob, you can gain some lines in your code by writing:

(let CXR (map (function intern) (explode (str X))) ... ) instead of using (function str->symlist).

Cheers,

vasil

unread,
Feb 6, 2012, 11:57:57 AM2/6/12
to qil...@googlegroups.com
Your code is good example of the most powerful features of Shen.

Minor changes may be done in CC part (some cleanup), as follows:

(defcc <expr> -*- := -*-;)
(defcc <a-d-to-head-tail>
"a" <a-d-to-head-tail> := [head <a-d-to-head-tail>];
"d" <a-d-to-head-tail> := [tail <a-d-to-head-tail>];
"r" <expr> := <expr>;)
(defcc <cxr?>
"c" "a" <a-d-to-head-tail> := [head <a-d-to-head-tail>];
"c" "d" <a-d-to-head-tail> := [tail <a-d-to-head-tail>];)

(defmacro mymacro
[X Y] <- (compile (function <cxr?>) (append (explode (str X))
[Y])))

vasil

unread,
Feb 6, 2012, 12:53:27 PM2/6/12
to qil...@googlegroups.com

BTW: Macroexpansion is done before typechecking. And building types with
build-cxrs is not necessary.


Types for cxr maybe generated in-place by macro:

(tc +)

\* first, introduce type for declare function *\
(datatype declare-type
let B1 (shen-decons B)
A : symbol;
___________________
(declare A B) : B1;)

\* second, make list of cxr symbols, which already have type signatures *\

(datatype cxr-typed-list
___________________________
(value cxr) : (list symbol);)

(set cxr [])

\* third, declare a function which checks and declare type for cxr *\

(define declare-type-for-cxr
{ (list string) --> symbol --> A }
["c" "a" | Rest] Sym -> (declare Sym [[list A] --> A])
["c" "d" | Rest] Sym -> (declare Sym [[list A] --> [list A]]))

(define check-and-declare
{ symbol --> boolean}
CXR -> false where (element? CXR (value cxr))
CXR -> (do (declare-type-for-cxr (explode (str CXR)) CXR) (set cxr
[CXR | (value cxr)]) true))

(tc -)
\* with (tc +) defcc does not work properly - fails with syntax error
later I'll try to figure out why *\

(defcc <expr> -*- := -*-;)

(defcc <chek-for-a-d-r>
"a" <chek-for-a-d-r> := skip;
"d" <chek-for-a-d-r> := skip;
"r" <expr> := (do (check-and-declare (head <expr>)) <expr>);)

(defcc <check-for-cxr?>
"c" "a" <chek-for-a-d-r> := skip;
"c" "d" <chek-for-a-d-r> := skip;)

(defmacro declare-types-for-cxr-inplace
[X Y] <- (compile (function <check-for-cxr?>) (append (explode (str X))
[X Y])))

Martial Boniou

unread,
Feb 7, 2012, 5:13:09 AM2/7/12
to qil...@googlegroups.com
Marvellous. That's exactly the kind of king size tip I wish to learn to move away from the unsecure world when I finalize a program (switch back and forth (tc +/-) is not my thing, you don't know in what mode you are when you load/use your program and there is no indication in defpackage to pass this information: ideally the maximum of functions should be excessible in both modes).

It would be great if shen-libs got a package to get datatypes of declare..., in order to type DECLARE and then DEFINE without {} if the type is to be able to code everytime in (tc +) mode if we want (except for Yacc for now).

To go back on my gist example, I do not use defmacro mymacro (I commented it actually) in order to auto-define a strict number of functions. Theoritically (function something) returns (fail) (or should) if I read the 'Shen Functions' page on Shen website correctly and if so, using mymacro to auto-generate functions may be obscure. How do we check CAR exists if it's not defined nor announced in *macros* ?

Anyway your explanation is great to understand how to build better program using typechecking, especially in these both cases (macro + defcc / eval + define + prolog + defcc). I hope the Shen Book will contain a lot of more examples than in the Qi Book.

Thanks,

At Mon, 06 Feb 2012 20:53:27 +0300,

> --
> You received this message because you are subscribed to the Google Groups "Qilang" group.
> To post to this group, send email to qil...@googlegroups.com.
> To unsubscribe from this group, send email to qilang+un...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/qilang?hl=en.
>

Reply all
Reply to author
Forward
0 new messages