Reading and expanding a Racket source file - racket

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

Related

"Docstrings" in Racket?

I know Racket doesn't have "docstrings" in the same way that many other languages do, but given how convenient documenting things at the source is, I'd like to approximate something like it in Racket.
When I first learned about Scribble and #langs, I thought it would be possible to do something like:
#lang racket
#lang scribble
... and then write code in Racket with docstrings in Scribble. But this doesn't work, probably because "languages don't compose."
#lang racket
(require scribble/manual)
#racket['hi]
which results in:
my-source.rkt:4:0: #racket: unbound identifier
I came across scribble/srcdoc which seems compelling because it sounds like it allows you to piggyback docs on top of contracts which already serve as a kind of minimal (typically module-level) documentation, in addition to providing runtime checks of course. I haven't been able to get it to work so far, but instead of thrashing around for another several hours I thought it would be more useful to ask about it here. For what it's worth, here's what I'm seeing at the moment:
#lang racket
(require scribble/srcdoc
(for-doc scribble/base scribble/manual))
(provide
(proc-doc/names fib
(-> integer? integer?)
(n)
#{Computes the #racket[n]th Fibonacci number}))
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))
which results in:
my-source.rkt:6:1: proc-doc/names: bad syntax
in: (proc-doc/names fib (-> integer? integer?) (n) # (Computes the #racket (n) th Fibonacci number))
Since reference docs like these are better at explaining how things work than how to use it, I'm looking for an answer that is more of a how-to on writing "docstrings" in Racket. It needn't be long, just sufficient to help the reader employ this "contract + docstring" pattern in their code (and, possibly, describing other alternatives).
You want the at-exp 'meta-language'. This lets you program in another language (in this case racket, with the modification of using at-expressions.
So taking your example above, you get:
#lang at-exp racket
(require scribble/srcdoc
(for-doc scribble/base scribble/manual))
(provide
(proc-doc/names fib
(-> integer? integer?)
(n)
#{Computes the #racket[n]th Fibonacci number}))
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1))
(fib (- n 2)))))
Note the at-exp in the first line.
You can also do:
#lang at-exp racket
(require scribble/manual)
#racket['hi]
and get:
(sized-element #f (list (cached-element #0=(style "RktVal" (list 'tt-chars (css-addition '(collects #"scribble" #"racket.css")) (tex-addition '(collects #"scribble" #"racket.tex")))) "'" ...) (cached-element #0# "hi" ...)) ...)

How to 'require' a Racket module that doesn't have a #lang header line?

As just one of many possible examples, break-example.rkt would be a perfectly valid Java program, except for the #lang mini-java header that Racket requires.
So e.g. if I've written a Java interpreter/compiler in Racket as a Racket module language, how can I say, "require this file Main.java which is written in module language mini-java but doesn't have any Racket-specific header"?
(Note that I have almost non-zero practical experience with Racket. I'm evaluating this for a specific use case I have for Racket + DrRacket, which has nothing to do with Java by the way. I searched the documentation but couldn't find any way to achieve this.)
I can’t run or test this right now, but maybe you can start from here and experiment with it. The main thing it uses is include/reader:
#lang racket
(require racket/include
syntax/parse/define
(for-syntax racket/syntax
racket/port
syntax/modread))
(define-simple-macro (require/mini-java path)
#:with modname (generate-temporary #'path)
(begin
(include/reader path (mini-java-reader 'modname))
(require 'modname)))
(begin-for-syntax
;; Symbol -> [Any InputPort -> Syntax]
(define ((mini-java-reader modname) src input)
(cond
[(port-closed? input) eof]
[else
(define stx
(with-module-reading-parameterization
(lambda ()
(read-syntax src
(input-port-append #t
(open-input-string "#lang mini-java\n")
input)))))
(close-input-port input)
(syntax-parse stx
[(module _ l . b)
#`(module #,modname l . b)])])))

Certain functions not loading into repl

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)).

How to get a function/macro definition from CL REPL?

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

Racket module contract confuse me

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.