how can I capture the expanded forms? - racket

I'm trying to capture the expanded forms by defining my own module-begin:
(define-syntax-rule (my-module-begin e ...)
(#%module-begin
e ...
(foo e ...)))
Am I correct that foo here gets the original forms? If so is there a way for foo to get the expanded forms instead?

To get the expanded forms you'll need to use local-expand in some way.
Part 1, an incomplete solution
You might think to call local-expand separately on every expression like this:
#lang racket
(require syntax/parse/define
(for-syntax syntax/stx))
(define-simple-macro (my-module-begin e ...)
; define a function that expands it
#:do [(define (expand/mod-ctx e)
(local-expand e 'module '()))]
; get the expanded versions by calling that function on the e's
#:with (e-expanded ...) (stx-map expand/mod-ctx #'(e ...))
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This works when the e forms are expressions like (+ 1 2) or (let ([x 3] [y 4]) (make-list x y)). However, it doesn't work when the e forms can be definitions.
Part 2, getting the expanded versions from Racket's #%module-begin
One way to support using local-expand with these module-level definitions is to wrap it in racket's #%module-begin form before expanding. This allows it to process all the es together in one call to local-expand.
(define-simple-macro (my-module-begin e ...)
; get the expanded versions by calling that function on a
; *constructed* module-begin form
#:with (_ e-expanded ...) (local-expand #'(#%module-begin e ...) 'module-begin '())
; use the expanded versions inside foo
(#%module-begin
e-expanded ...
(foo e-expanded ...)))
This gets Racket's #%module-begin to handle the definitions, and when it's done, you can pattern match on it with (_ e-expanded ...).

Related

Macro-defining macro in Racket?

In Common Lisp it is relatively easy to create a macro-defining macro. For example, the following macro
(defmacro abbrev (short long)
`(defmacro ,short (&rest args)
`(,',long ,#args)))
is a macro-defining macro, because it expands to another macro.
If we now put
(abbrev def defun)
in our program, we can write def instead of defun whenever we define a new function.
Of course, abbrev can be used for other things, too. For example, after
(abbrev /. lambda)
we can write (/. (x) (+ x 1)) instead of (lambda (x) (+ x 1)). Nice. (For detailed explanation of abbrev, see http://dunsmor.com/lisp/onlisp/onlisp_20.html)
Now, my questions are:
Can I write the macro-defining macros in Racket?
If I can, how to do that? (for example, how to write something similar to
abbrev macro in Racket?)
According to this part of the Racket Guide:
(define-syntax-rule (abbrev short long)
(define-syntax-rule (short body (... ...))
(long body (... ...))))
Quoting the above link:
The only non-obvious part of its definition is the (... ...), which
“quotes” ... so that it takes its usual role in the generated macro,
instead of the generating macro.
Now
(abbrev def define)
(abbrev /. lambda)
(def f (/. (x) (+ x 1)))
(f 3)
yields
4
FWIW, it works on Guile as well, so it's no Racket-specific thing.
ad 1. Yes.
ad 2. Your example can most easily be written
#lang racket
(define-syntax (abbrev stx)
(syntax-case stx ()
[(_ short long)
#'(define-syntax short (make-rename-transformer #'long))]))
(abbrev def define)
(def x 42)
x
The example above evaluates to 42.
I find that renaming can be done simply with define or let statements:
(define =? =)
(define lr list-ref)
or:
(let ((=? =)
(lr list-ref))
(println (lr '(1 2 3) 2))
(println (=? 1 2))
(println (=? 1 1)))
Output:
3
#f
#t
There seem to be no need for any macro for this purpose.

Nested macros in Racket

I want to be able to write a nested expression like this:
(AND/OR expr1 op1 expr2 AND/OR expr3 op2 expr4 and so on)
Where AND/OR is essentially AND or OR. But I want to be able to write an infinite amount of them. I'm using the define-syntax to try to make this happen but I'm not sure how to accept infinite amounts of nested expressions.
Don't mind the expr's and op's in my example, that part I can handle myself. I only want to know how to accept infinite nesting.
Example:
(SELECT somecolumns
FROM sometable
WHERE something
AND/OR something
AND/OR (something AND/OR something)
AND/OR ...)
As Asumu says, in general it's simpler to deal with s-expressions, at least in order to ensure correct operator priority, but for some simple cases pattern matching of syntax-rules (and syntax-parse and co) makes this easy, using rest arguments and recursive matching:
#lang racket
(define-syntax parse-args
(syntax-rules (AND) ; treat AND as a literal
[(_)
; no more argument, return value:
'()]
[(_ (arg1 AND in-rst ...))
; Composed argument found, call parse-args recursively:
(parse-args arg1 AND in-rst ...)]
[(_ arg1 AND rst ...)
; AND operator found, parse left side and rest
(list 'and
; parse the argument (may be composed or not):
(parse-args arg1)
; then parse the rest of the arguments:
(parse-args rst ...))]
[(_ arg)
; in case the argument is not composed or does not contain AND, don't parse it
arg]))
;; TESTS:
(parse-args 'a AND ('b AND 'bb) AND 'c AND 'f)
; -> '(and a (and (and b bb) (and c f)))
(parse-args 'a AND ('b AND 'bb))
; -> '(and a (and b bb))
However, note that the above code can become impractical when adding other operators.
Edit:
Together with the select macro:
(define-syntax SELECT
(syntax-rules (FROM WHERE)
[(_ select FROM from WHERE where ...)
(list 'Select select 'From from 'Where (parse-args where ...))]))
; TEST:
(SELECT 'somecolumns
FROM 'sometable
WHERE 'something1
AND 'something2
AND ('something3 AND 'something4)
AND 'blop)
; ->
#;'(Select
somecolumns
From
sometable
Where
(and something1
(and something2
(and (and something3 something4) blop))))
Again, pattern-matching allows for cutting the list at the right point to get the rest arguments

Higher Order Function Syntax in Common Lisp

I'm teaching myself Common Lisp using Norvig's Paradigms of AI Programming and came across something I didn't understand and he didn't explain.
(defun mappend (fn the-list)
(apply #'append (mapcar fn the-list)))
What is the difference between calling a higher order function as follows, higherOrderFunc #'funcName funcArg and what he does when calling mapcar without #'? Is #' necessary when calling a higher order function?
Common Lisp has different namespaces for functions and variables.
(defun mappend (fn the-list)
(apply #'append (mapcar fn the-list)))
Above MAPPEND gets defined with two local variables fn and the-list
APPLY gets passed the function value of APPEND.
MAPCAR gets passed the variable value of FN.
Similar see this:
CL-USER 129 > (flet ((add-something (number)
(+ number 17)))
(let ((add-something (lambda (number)
(+ number 42))))
(list
(mapcar #'add-something '(1 2 3))
(mapcar add-something '(1 2 3)))))
->
((18 19 20) (43 44 45))
LET creates local variables, FLET creates local functions.
The first mapcar uses the function namespace and the second uses the variable namespace.
Common Lisp uses a special function namespace because it was thought to be more efficient (slightly easier to implement a fast Lisp) and to allow functions and variables to have the same name.
In Common Lisp we can write:
(defun list-me (list)
(list list))
In Scheme, which does not have separate namespaces one would write something like this:
(define (list-me lst)
(list lst))
#' is syntactic sugar for function: #'foo is read as (function foo).
Function is a special operator that returns the function value bound to the name given. If you pass a function as a parameter, that parameter (in your case, fn) has its value bound to the function. To pass it on to another function, you can simply put the variable name into the call form. However, to get the function value of a name, you need to access it with function.
Using #' is not strictly required. If instead you simply pass 'foo the symbol-function will be invoked. Consider the following:
* (defvar foo #'(lambda (a) 'var))
* (setf (symbol-function 'foo) #'(lambda (a) 'fun))
* (mapcar 'foo '(a b))
(FUN FUN)
* (mapcar #'foo '(a b))
(FUN FUN)
* (mapcar foo '(a b))
(VAR VAR)
Practially #'foo or 'foo are equivalent:
X3J13 voted [...] to allow the 'function' to the only of type 'symbol'
or 'function'; [...] one must use the 'function' special form [...]
before a lambda-expression [...].
Specification of the function in flet has some interesting properties:
* (flet ((foo (a) 'FLET))
(mapcar foo '(a b))) ; Uses 'value' of foo
(VAR VAR)
* (flet ((foo (a) 'FLET))
(mapcar 'foo '(a b))) ; Uses 'function' of foo
(FUN FUN)
* (flet ((foo (a) 'FLET))
(mapcar #'foo '(a b))) ; Uses local binding 'flet' of foo
(FLET FLET)

When should I use syntax/loc instead of #' (aka syntax)?

A new syntax object can be constructed by both syntax/loc and syntax (also written #').
When should I use syntax/loc?
Use #' (i.e. syntax) when you are not constructing a new syntax object, as when you're just referencing a pattern variable bound with syntax-case or with-syntax.
Use #' for temporary syntax objects as in (syntax->list #'(id ...)).
Use #' for syntax objects representing forms that you know won't have syntax errors in them, or where syntax errors in them are the fault of your macro implementation, not the use of your macro.
Use syntax/loc when you construct expressions that potentially can contain syntax-errors due to an incorrect usage of your macro.
Let's consider a concrete example:
The form display-let should work exactly like normal let, except that it displays the values of the bindings before it evaluates the body.
Here is a first implementation:
(define-syntax (display-let-1 stx)
(syntax-case stx ()
[(_ ([id expr] ...) body ...)
#'((lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
expr ...)]))
Here is an example of a correct use of the macro:
> (display-let-1 ([x 1] [y 2]) (+ x y))
x is bound to 1
y is bound to 2
3
Now let us see what happens when the macro is used incorrectly:
> (display-let-1 ())
lambda: bad syntax in: (lambda ())
This usage is incorrect, since a use of let must always have a non-empty body. Besides printing the error message, DrRacket colors this code red:
(lambda (id ...)
(displayln (format "~a is bound to ~a" 'id id)) ...
body ...)
Although it is correct that the lambda expression constructed by the macro is incorrect, (lambda ()) is not legal, it is not due to an error in the macro, but due to an incorrect use of the macro.
To redirect the blame surround the constructed lambda expression with syntax/loc and use the first argument of syntax/loc as place to color red.
(define-syntax (display-let-2 stx)
(syntax-case stx ()
[(display-let ([id expr] ...) body ...)
#`(#,(syntax/loc stx (lambda (id ...) body ...)) expr ...)]))
> (display-let-2 ())
display-let-2: bad syntax in: (display-let-2 ())
This time around the (display-let-2 ()) entered in the repl is colored red, and the error message mentioned display-let-2 instead of lambda.

While Loop Macro in DrRacket

I am trying to create a macro for while loop in DrRacket. Here is what I wrote:
(require mzlib/defmacro)
(define-macro my-while
(lambda (condition body)
(list 'local (list (list 'define (list 'while-loop)
(list 'if condition
(list body (list 'while-loop))
'(void))))
'(while-loop))))
(define x 0)
(my-while (< x 10)
(begin
(display x)
(newline)
(set! x (+ x 1))))
The output of this program is:
0
1
2
3
4
5
6
7
8
9
error: procedure application: expected procedure, given: #<void>; arguments were: #<void>
Can someone help me with this? Why wouldn't this macro just terminate and return void. It seems that when the condition is not true, the system tries to apply the void as an argument to some procedure.
Ouch:
Using this style of while loop encourages excessive use of imperative programming.
Using define-macro creates unhygienic macros, which is a nightmare in Scheme.
While I don't encourage writing an imperative-style loop macro, for your reference, here's a non-define-macro version of the same macro:
(define-syntax-rule (my-while condition body ...)
(let loop ()
(when condition
body ...
(loop))))
It uses syntax-rules, which creates hygienic macros, and is much, much easier to read than what you have.
Now, for the actual answer for your question, first, let's write your original macro out in a more readable way:
(define-macro my-while
(lambda (condition body)
`(local ((define (while-loop)
(if ,condition
(,body (while-loop))
(void))))
(while-loop))))
Once you write it out this way, you can see where the real problem is: in the (,body (while-loop)) line, which should instead have been (begin ,body (while-loop)).
Why use a macro when a plain old function will do?
;; fun-while : (-> Boolean) (-> Any) -> Void
(define (fun-while condition body)
(when (condition)
(body)
(fun-while condition body))
Of course, this requires you to pass in repeatable actions that can be called (this is why condition and body are surrounded with parens in the body of fun-while), so you do need a macro if you want prettier syntax. But once you have a function that has the desired behavior, putting some sugar on top is trivial for this case:
(define-syntax-rule (my-while condition body ...)
(fun-while (lambda () condition)
(lambda () body ...)))
Now, as has been said, this encourages imperative style, which is frowned upon. Instead of mutation, try making the state explicit instead:
;; pure-while : forall State.
;; (State -> Boolean) ; the "condition" that inspects the state
;; (State -> State) ; the "body" that moves from one state to the next
;; -> ; curried
;; State ; the current state
;; -> State ; produces the ending state
(define ((pure-while condition make-next) current-state)
(if (condition current-state)
(pure-while condition make-next (make-next current-state))
current-state))
You'll notice that the first two arguments are now functions from State to something, and the result of applying to 2 arguments is also a function from State -> State. This is a recurring pattern that, as a Haskeller, I'd call the "State Monad". Discussion of putting sugar on top of this concept is a little beyond the scope of this conversation, though, so I'll just stop there.
Another version of while uses a do loop:
(define-syntax while
(syntax-rules ()
((while pred? stmt ...)
(do () ((not pred?))
stmt ...))))
Because it's been a while:
a while macro for Racket 6.0
#lang racket
(define-syntax while
(syntax-rules ()
((_ pred? stmt ...)
(do () ((not pred?))
stmt ...))))