I currently am putting unit tests at the bottom of the file I'm working on, like this:
(provide foo)
(define (bar x) (+ 1 x))
;; unit tests
(module+ test
(require racket/pretty)
(define testcases '(2 3 4))
(for ([test testcases])
(pretty-print (bar test))))
This works, but I want to avoid repeating the boilerplate unit test code for all my modules. Having never written a macro in Racket before, I'm unsure how to get the various parts to fit together.
I would like to have the following code expand to the boilerplate version above:
(provide foo)
(define (bar x) (+ 1 x))
;; unit tests
(test foo '(2 3 4))
For the test macro, are you sure you need to generate a require from the macro? You can have the test macro generate a use of pretty-print if racket/pretty is required in the file that defines test, and then it doesn't matter whether there's a require in the file that uses test.
For example if you have two files macro.rkt and use.rkt:
file macro.rkt:
#lang racket
(provide test)
(require racket/pretty
syntax/parse/define)
(define-simple-macro (test fn:id args:expr)
(module+ test
(define testcases args)
(for ([test testcases])
(pretty-print (fn test)))))
file use.rkt:
#lang racket
(require "macro.rkt")
(provide foo)
(define (foo x) (+ 1 x))
;; unit tests
(test foo '(2 3 4))
Then the reference to pretty-print works in the output of the macro even though it's not normally available in use.rkt. It works because pretty-print gets its scope from the macro definition site, not the use site.
Does this work for your problem?
Related
Working through Little Schemer,
We're required to define a few of our own functions.
I've defined them, only add1 and sub1 appear in the repl after it loads. I'm using Racket v7.0.
#lang racket
(provide atom? add1 sub1)
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
(define add1
(lambda (x)
(+ x 1)))
(define sub1
(lambda (x)
(- x 1)))
I cannot figure out why (atom?) does not load. When I copy paste the s-expression into repl it works. Any ideas?
Since you are unsing #lang racket and provide the correct way to use the file is with require.
$ ls
toys.rkt
$ racket
Welcome to Racket v6.8.
> (require "toys.rkt")
> (atom? '())
#f
So imagine you make a program like this:
#lang racket
(require "toys.rkt")
(if (atom? 'test)
'atom
'no-atom)
You save it and run it:
$ racket program.rkt
'atom
Also note that you can use R6RS and make toys a library. You then need to use plt-r6rs --install toys.rkt and then use (import (rnrs base) (toys)).
I need to read a Racket source file and run it through macro expansion. I have a simple test file that Racket itself happily accepts:
C:\ayane>type factorial.rkt
#lang racket
(provide factorial)
(define (factorial n)
(if (<= n 1)
1
(* n (factorial (sub1 n)))))
Now I try from the REPL:
C:\ayane>racket
Welcome to Racket v6.5.
> (read-accept-reader #t)
> (expand (with-input-from-file "factorial.rkt" (lambda () (read-syntax "factorial.rkt"))))
#<syntax::1 (module factorial racket (#%m...>
So far so good. Now the same thing from a test program:
C:\ayane>type test.rkt
#lang racket
(read-accept-reader #t)
(expand (with-input-from-file "factorial.rkt"
(lambda ()
(read-syntax "factorial.rkt"))))
C:\ayane>racket test.rkt
factorial.rkt::1: module: unbound identifier;
also, no #%app syntax transformer is bound
at: module
in: (module factorial racket (#%module-begin (provide factorial) (define (factorial n) (if (<= n 1) 1 (* n (factorial (sub1 n)))))))
context...:
C:\ayane\test.rkt: [running body]
So it looks like the same code works interactively but not in a program. What am I missing?
You need to specify which namespace expand should use to lookup top-level variables (i.e. variables not bound in the program).
For example:
(parameterize ([current-namespace (make-base-namespace)])
(expand ...))
For more information see the comments in the file below in which I attempt to explain the relationship between namespaces and expand:
https://github.com/soegaard/meta/blob/master/runtime/racket-eval.rkt#L122
The answer from #soegaard addresses the immediate issue, but if you want a comprehensive program that reimplements expansion from primitives, you can look at
https://github.com/samth/pycket/blob/master/pycket/pycket-lang/expand.rkt
Is there an easy way for me to load a submodule in the current file in racket-mode in emacs?
For example if I have the following file
#lang racket
(define (foo x)
x)
(module+ sub
(define (bar x y)
x))
and I hit f5 in racket-mode to start the repl then foo is available but bar is not.
You can combine dynamic-enter! and quote-module-path to do this.
Given a repl interaction for the code above that you posted:
> (require racket/enter syntax/location)
> (dynamic-enter! (quote-module-path sub))
> bar
#<procedure:bar>
Alternatively, you could use dynamic-require/expose (the expose part allows you require things that are not provided), as done here.
It works the same way in DrRacket. You have to provide bar from the submodule, and require the submodule to use it. Try the following code:
#lang racket
(define (foo x)
x)
(module+ sub
(define (bar x y)
x)
(provide bar))
;; (bar 1 2) -- undefined
(require (submod "." sub))
(bar 1 2) ;; -- works here
I've got another question involving self-reference in Common Lisp. I found a thread on Stack Exchange which poses a problem of writing the shortest program that would print all printable ASCII characters NOT present in the program's source code. This got me thinking how to tackle the problem in Common Lisp. I hit against two problems - one probably trivial, the other more tricky:
First is the case of writing a CL script, e.g. starting with #!/usr/bin/env sbcl --script. I thought that through *posix-argv* I could access all command line arguments including the name of the called script. I also looked for the equivalent of Bash $0 but could find none. What worked for me in the end is this ugly Bash-ified SBCL script, which explicitly passes $0 to SBCL and proceeds from that:
#!/bin/bash
#|
sbcl --script $0 $0
exit
|#
(defun file-string (path)
(with-open-file (stream path)
(let ((data (make-string (file-length stream))))
(read-sequence data stream)
data)))
(let* ((printable (mapcar #'code-char (loop for i from #x20 to #x7e collect i)))
(absent (set-difference
printable
(coerce (file-string (cadr *posix-argv*)) 'list))))
(print (coerce absent 'string)))
My question regarding this point is: can you think of any way of doing it without relying so heavily on Bash supplying relevant arguments? Or, more briefly: is there a CL (SBCL in particular) equivalent of $0?
Now comes the part that I'm totally puzzled with. Before resorting to the script approach above I tried to accomplish this goal in a more REPL-oriented way. Based on the &whole specifier in defmacro and considerations in this thread I've tried to get the name of the macro from the &whole argument and somehow "read in" its source. And I have absolutely no idea how to do it. So in short: given the name of the macro, can I somehow obtain the defmacro form which defined it? And I'm talking about a generic solution, rather than parsing the REPL history.
EDIT: Regarding mbratch's question about use of macroexpand-1 here's how I do it:
(defmacro self-refer (&whole body)
(macroexpand-1 `',body))
With this call I'm able to obtain (SELF-REFER) by calling (SELF-REFER). Which isn't much of a solution...
I hope someone could point me in the right direction. Thanks!
Getting the source of a macro is not defined in Common Lisp.
This may work (Example from LispWorks):
CL-USER 10 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER 11 > (pprint (function-lambda-expression (macro-function 'foo)))
(LAMBDA
(DSPEC::%%MACROARG%% #:&ENVIRONMENT1106 &AUX (#:&WHOLE1107 DSPEC::%%MACROARG%%)
(#:\(A\ ...\)1108 (CDR #:&WHOLE1107))
(#:CHECK-LAMBDA-LIST-TOP-LEVEL1110
(DSPEC::CHECK-LAMBDA-LIST-TOP-LEVEL '(A B)
#:&WHOLE1107
#:\(A\ ...\)1108
2
2
'NIL
:MACRO))
(A (CAR (DSPEC::THE-CONS #:\(A\ ...\)1108)))
(#:\(B\)1109 (CDR (DSPEC::THE-CONS #:\(A\ ...\)1108)))
(B (CAR (DSPEC::THE-CONS #:\(B\)1109))))
(DECLARE (LAMBDA-LIST A B))
(BLOCK FOO `(* (+ ,A ,B) (+ ,A ,A))))
An even more esoteric way is to alter the existing DEFMACRO to record its source.
Many Lisp implementations have a non-standard feature called advising. LispWorks for example can advise macros:
CL-USER 31 > (defadvice (defmacro source-record-defmacro :after)
(&rest args)
(setf (get (second (first args)) :macro-source) (first args)))
T
Above adds code to the standard DEFMACRO macro, which records the source on the symbol property list of the macro name. defmacro is the name of the thing to advise. source-record-defmacro is the chosen name of this advice. :after then specifies that the code should run after the normal defmacro code.
CL-USER 32 > (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER 33 > (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
Again, this is completely non-standard - I'm not sure if a comparable mechanism exists for SBCL, though it has something called 'encapsulate'.
A very belated followup to Rainer Joswig's LispWorks solution. I've been using Allegro CL lately and discovered the fwrap facility. Conceptually it's very similar to the defadvice above and slighly more verbose. Here's a re-iteration of Rainer's example in ACL 10.0:
(def-fwrapper source-record-defmacro (&rest args)
(setf (get (second (first args)) :macro-source) (first args))
(call-next-fwrapper))
Having defined an fwrapper you need to "put it into action" explicitly:
(fwrap 'defmacro 'srd 'source-record-defmacro)
After this it's like in Rainer's example:
CL-USER> (defmacro foo (a b) `(* (+ ,a ,b) (+ ,a ,a)))
FOO
CL-USER> (pprint (get 'foo :macro-source))
(DEFMACRO FOO (A B) `(* (+ ,A ,B) (+ ,A ,A)))
; No value
the module: test-define.rkt
#lang racket
(provide test)
(provide (contract-out [add-test! (-> void)]))
(define test 0)
(define (add-test!)
(set! test (add1 test)))
the main program:act.rkt
#lang racket
(require "test-define.rkt")
(printf "~a~%" test)
(add-test!)
(printf "~a~%" test)
run the act.rkt, I get:
0
1
this is what I want.
But if I change the contract in test-define.rkt:
(provide test)
change to
(provide (contract-out [test integer?]))
then I run the act.rkt again, I get:
0
0
Why? I can't change the test value.
If I provide a get func, it turns normal again.
(provide (contract-out [get-test (-> integer?)]))
(define (get-test)
test)
If test's type change to hash map, it's always normal.
What I missed?
I notice that in test-define.rkt you have this line
(set! test3 (add1 test))
Should test3 be test ?
This might explain why you saw that two zeros (test never changed).
EDIT 2
For convenience I put your two modules in the same file
and changed the contract of test:
#lang racket
(module test-define racket
(provide test)
; (provide (contract-out [test integer?]))
(provide get-test)
(provide (contract-out [add-test! (-> void)]))
(define test 0)
(define (add-test!)
(set! test (add1 test)))
(define (get-test)
test))
(module ack racket
(require (submod ".." test-define))
(printf "~a~%" test)
(add-test!)
(printf "~a~%" test))
(require (submod "." ack))
Now I see the 0 1 vs 0 0 output as you do.
Hmmm. Why?
Well. If we change the provide forms to use no contracts
at all, the output is 0 1.
Adding a contract shouldn't change this behaviour (I think).
Maybe a bug?
http://pre.racket-lang.org/docs/html/guide/contracts-gotchas.html?q=contract&q=ignore
Says:
The contract library assumes that variables exported via contract-out
are not assigned to, but does not enforce it. Accordingly, if you try
to set! those variables, you may be surprised. ...snip... Moral: This
is a bug that we will address in a future release.