I am trying to write a small scheme-like language in python, in order to try to better understand scheme.
The problem is that I am stuck on syntax objects. I cannot implement them because I do not really understand what they are for and how they work.
To try to understand them, I played around a bit with syntax objects in DrRacket.
From what I've been able to find, evaluating #'(+ 2 3) is no different from evaluating '(+ 2 3), except in the case that there is a lexical + variable shadowing the one in the top-level namespace, in which case (eval '(+ 2 3)) still returns 5, but (eval #'(+ 2 3)) just throws an error.
For example:
(define (top-sym)
'(+ 2 3))
(define (top-stx)
#'(+ 2 3))
(define (shadow-sym)
(define + *)
'(+ 2 3))
(define (shadow-stx)
(define + *)
#'(+ 2 3))
(eval (top-sym)), (eval (top-stx)), and (eval (shadow-sym)) all return 5, while (eval (shadow-stx)) throws an error. None of them return 6.
If I didn't know better, I would think that the only thing that's special about syntax objects (aside from the trivial fact that they store the location of the code for better error reporting) is that they throw an error under certain circumstances where their symbol counterparts would have returned a potentially unwanted value.
If the story were that simple, there would be no real advantage to using syntax objects over regular lists and symbols.
So my question is: What am I missing about syntax objects that makes them so special?
Syntax objects are the repository for lexical context for the underlying Racket compiler. Concretely, when we enter program like:
#lang racket/base
(* 3 4)
The compiler receives a syntax object representing the entire content of that program. Here's an example to let us see what that syntax object looks like:
#lang racket/base
(define example-program
(open-input-string
"
#lang racket/base
(* 3 4)
"))
(read-accept-reader #t)
(define thingy (read-syntax 'the-test-program example-program))
(print thingy) (newline)
(syntax? thingy)
Note that the * in the program has a compile-time representation as a syntax object within thingy. And at the moment, the * in thingy has no idea where it comes from: it has no binding information yet. It's during the process of expansion, during compilation, that the compiler associates * as a reference to the * of #lang racket/base.
We can see this more easily if we interact with things at compile time. (Note: I am deliberately avoiding talking about eval because I want to avoid mixing up discussion of what happens during compile-time vs. run-time.)
Here is an example to let us inspect more of what these syntax objects do:
#lang racket/base
(require (for-syntax racket/base))
;; This macro is only meant to let us see what the compiler is dealing with
;; at compile time.
(define-syntax (at-compile-time stx)
(syntax-case stx ()
[(_ expr)
(let ()
(define the-expr #'expr)
(printf "I see the expression is: ~s\n" the-expr)
;; Ultimately, as a macro, we must return back a rewrite of
;; the input. Let's just return the expr:
the-expr)]))
(at-compile-time (* 3 4))
We'll use a macro here, at-compile-time, to let us inspect the state of things during compilation. If you run this program in DrRacket, you will see that DrRacket first compiles the program, and then runs it. As it compiles the program, when it sees uses of at-compile-time, the compiler will invoke our macro.
So at compile-time, we'll see something like:
I see the expression is: #<syntax:20:17 (* 3 4)>
Let's revise the program a little bit, and see if we can inspect the identifier-binding of identifiers:
#lang racket/base
(require (for-syntax racket/base))
(define-syntax (at-compile-time stx)
(syntax-case stx ()
[(_ expr)
(let ()
(define the-expr #'expr)
(printf "I see the expression is: ~s\n" the-expr)
(when (identifier? the-expr)
(printf "The identifier binding is: ~s\n" (identifier-binding the-expr)))
the-expr)]))
((at-compile-time *) 3 4)
(let ([* +])
((at-compile-time *) 3 4))
If we run this program in DrRacket, we'll see the following output:
I see the expression is: #<syntax:21:18 *>
The identifier binding is: (#<module-path-index> * #<module-path-index> * 0 0 0)
I see the expression is: #<syntax:24:20 *>
The identifier binding is: lexical
12
7
(By the way: why do we see the output from at-compile-time up front? Because compilation is done entirely before runtime! If we pre-compile the program and save the bytecode by using raco make, we would not see the compiler being invoked when we run the program.)
By the time the compiler reaches the uses of at-compile-time, it knows to associate the appropriate lexical binding information to identifiers. When we inspect the identifier-binding in the first case, the compiler knows that it's associated to a particular module (in this case, #lang racket/base, which is what that module-path-index business is about). But in the second case, it knows that it's a lexical binding: the compiler already walked through the (let ([* +]) ...), and so it knows that uses of * refer back to the binding set up by the let.
The Racket compiler uses syntax objects to communicate that kind of binding information to clients, such as our macros.
Trying to use eval to inspect this sort of stuff is fraught with issues: the binding information in the syntax objects might not be relevant, because by the time we evaluate the syntax objects, their bindings might refer to things that don't exist! That's fundamentally the reason you were seeing errors in your experiments.
Still, here is one example that shows the difference between s-expressions and syntax objects:
#lang racket/base
(module mod1 racket/base
(provide x)
(define x #'(* 3 4)))
(module mod2 racket/base
(define * +) ;; Override!
(provide x)
(define x #'(* 3 4)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require (prefix-in m1: (submod "." mod1))
(prefix-in m2: (submod "." mod2)))
(displayln m1:x)
(displayln (syntax->datum m1:x))
(eval m1:x)
(displayln m2:x)
(displayln (syntax->datum m2:x))
(eval m2:x)
This example is carefully constructed so that the contents of the syntax objects refer only to module-bound things, which will exist at the time we use eval. If we were to change the example slightly,
(module broken-mod2 racket/base
(provide x)
(define x
(let ([* +])
#'(* 3 4))))
then things break horribly when we try to eval the x that comes out of broken-mod2, since the syntax object is referring to a lexical binding that doesn't exist by the time we eval. eval is a difficult beast.
Related
I was wondering if you're allowed to call another program you made to do work in a new program you are about to make in scheme, or would I have to copy and paste all the code from the previous program, though I can do this and make my life simple, I'm wondering if there is a more sophisticated elegant way to import in scheme r5rs.
;; Here is an example of what I mean
;; for example I have a file name add.scm which adds 2 numbers
;; now I want to make a new function that squares the numbers
;;is there a way I can do something like this
#lang add.scm as add
;;and use it here like so
(define (square x)
(* x x))
(square add)
;;where add already returns a value
This may seem like a silly piece of code, but this is the best pesudo code I can give, if the example needs more editing to understand please let me know, thank you.
If I understand your question, you have this module named add.scm:
;; add.scm
#lang racket
(+ 5 7) ;; prints 12 when run
and you want to write a new module that gets the value that the add.scm module prints out, bind it to a variable, and use it in a computation, like this:
;; square.scm
#lang racket
(??? add ??? "add.scm" ???) ;; bind `add` to "value" of "add.scm" module
(* add add) ;; prints 144 when run
No, there is no easy way to do that. It's possible, by using dynamic-require or a subprocess to run the module, capturing the output and then reading it to get the value, but that's an awful, complicated, brittle way to do things.
In Racket, a better approach would be for add.rkt to define and export a variable and have a main submodule that prints the value:
;; add.rkt
#lang racket
(provide x)
(define x (+ 5 7))
(module+ main
x)
Then you can use (require "add.rkt") from another module to get x to use in computations, and if you run add.rkt as a program (for example, with racket add.rkt), then it prints the value.
Racket (which has #lang as in the question, and module/provide/require as explained in another answer) is not Scheme (let alone R5RS).
In R6RS Scheme, Scheme source can be divided between library files and top-level programs
If the file add-library.scm contains:
(library (add-library)
(export add)
(import (rnrs))
(define add (+ 5 7)) )
and add-toplevel.scm contains:
(import (add-library))
(define (square x)
(* x x))
(display (square add))
Then:
$ scheme
> (load "add-toplevel.scm")
144
>
This is not a duplicate of
set-car!, set-cdr! unbound in racket? or
of
Implement SICP evaluator using Racket
or of
How to install sicp package module in racket?,
but rather a follow-up question because the solutions proposed therein do not
work for me. First, the need: Section 5.5.5 of SICP, the compiler plus
explicit-control evaluator (code here in "ch5-eceval-compiler.scm"), are
entirely dependent on set-car! and set-cdr! into explicit quoted lists. I
would like to copy and modify this code without a complete, bottom-up rewrite in
immutable form. I'd also accept a reference to a scheme implementation that can
run the code out-of-the-box or with some minimal, straightforward adaptation,
i.e., a scheme that has set-car! and set-cdr! or some
work-around. Neither guile nor racket give me an easy time running this code.
EDIT: mit scheme will load the eceval compiler. I'm leaving the question up for those who might want to get it going in racket (I would rather, for example).
Here is a deeper explanation, including the things I explored and tried out, and
how I diagnosed the quoted list as the deepest problem. When I hand-converted
the quoted list into an mquoted nest of mlists, the code broke in much worse
ways and the rabbit hole got much deeper. I had to revert after a couple of
hours of delicate brain surgery that failed.
Here is an MVE of the kind of structure that section 5.5.5 relies on. This is small, but structurally like the real thing:
(define foo '(a b))
(set-cdr! foo '(c))
The real thing starts like this:
(define eceval
(make-machine
'(exp env val proc argl continue unev
compapp ;*for compiled to call interpreted
)
eceval-operations ;; ----------------------------------------------
'( ;; <<<<<<<<======== BIG QUOTED LIST CAUSING TROUBLE / NOT MCONSES!
;;SECTION 5.4.4, as modified in 5.5.7 ;; -------------------------------
;;*for compiled to call interpreted (from exercise 5.47)
(assign compapp (label compound-apply))
;;*next instruction supports entry from compiler (from section 5.5.7)
(branch (label external-entry))
read-eval-print-loop
(perform (op initialize-stack))
(perform
(op prompt-for-input) (const ";;; EC-Eval input:"))
...
and goes on for quite a while. The evaluator is the "machine-code" in the quoted
list, and various generated code does set-car! and set-cdr! into registers
and environment frames and other things. The code fails on load.
There seems to be no easy way to convert the evaluator into immutable form
without a full rewrite, and I'm trying to avoid that. Of course, set-car! and
set-cdr! are not available in #lang racket, and I don't think they're in
guile, either (at least guile refused to load "ch5-eceval-compiler.scm,"
throwing a mutability error, on which I did not dig deeper).
One solution proposed in
set-car!, set-cdr! unbound in racket? is
to rewrite the code using mcons, mcar, mlist, etc. according to (require
compatibility/mlist) (require rnrs/mutable-pairs-6). Those compatibility
packages have no replacement for quote, so I tried writing my own mquote. I
spent a couple of hours on such a refactoring, but the exercise was not
converging, just going deeper and deeper down the rabbit hole and ending up with
even deeper problems. It seems that to pursue even a refactoring I must
understand more semantics about "ch5-eceval-compiler.scm," and if I must, I
might as well rewrite it in immutable form.
Easier solutions proposed in
set-car!, set-cdr! unbound in racket?
are to use #lang sicp or #lang r5rs. There follows three experiments that
referenced other answers on stack overflow:
#lang r5rs
(define foo '(a b))
(set-cdr! foo '(c))
foo
Error: struct:exn:fail:contract:variable
set-cdr!: undefined;
cannot reference an identifier before its definition
in module: "/usr/share/racket/pkgs/r5rs-lib/r5rs/main.rkt"
-----------------------------------------------
which points to a place where set-cdr! is clearly defined:
...
(module main scheme/base
(require scheme/mpair
racket/undefined
(for-syntax scheme/base syntax/kerncase
"private/r5rs-trans.rkt")
(only-in mzscheme transcript-on transcript-off))
(provide (for-syntax syntax-rules ...
(rename-out [syntax-rules-only #%top]
[syntax-rules-only #%app]
[syntax-rules-only #%datum]))
(rename-out
[mcons cons]
[mcar car]
[mcdr cdr]
[set-mcar! set-car!] ;; --------------------------
[set-mcdr! set-cdr!] ;; <<<<<<<<======== LOOK HERE
[mpair? pair?] ;; --------------------------
[mmap map]
[mfor-each for-each])
= < > <= >= max min + - * /
abs gcd lcm exp log sin cos tan not eq?
call-with-current-continuation make-string
symbol->string string->symbol make-rectangular
exact->inexact inexact->exact number->string string->number
...
Here is a similar failure with #lang sicp
#lang sicp
(define foo '(a b))
(set-cdr! foo '(c))
foo
Error: struct:exn:fail:contract:variable
set-cdr!: undefined;
cannot reference an identifier before its definition
in module: "/home/rebcabin/.racket/7.2/pkgs/sicp/sicp/main.rkt"
----------------------------------------------------
pointing to code that only indirectly defines set-cdr!, but clearly in the
appropriate package:
....
#lang racket
(require racket/provide ;; --------------------------------------------
(prefix-in r5rs: r5rs) ;; <<<<<<<<======== PULL IN SET-CDR! ETC. HERE?
(rename-in racket [random racket:random])) ;; ------------------------
(provide (filtered-out (λ (name) (regexp-replace #px"^r5rs:" name ""))
(except-out (all-from-out r5rs) r5rs:#%module-begin))
(rename-out [module-begin #%module-begin]))
(define-syntax (define+provide stx)
(syntax-case stx ()
[(_ (id . args) . body) #'(begin
(provide id)
(define (id . args) . body))]
[(_ id expr) #'(begin
(provide id)
(define id expr))]))
...
I dig deeper into
Implement SICP evaluator using Racket
and find
(require (only-in (combine-in rnrs/base-6
rnrs/mutable-pairs-6)
set-car!
set-cdr!))
(define foo '(a b))
(set-cdr! foo '(c))
foo
yielding
Error: struct:exn:fail:contract
set-mcdr!: contract violation
expected: mpair?
given: '(a b)
argument position: 1st
other arguments...:
'(c)
This error implies that the problem really is the quoted list. I don't have an
easy way to make the big quoted list in eceval into an mlist or chain of
mcons. I tried it and it's very verbose and error prone, plus I think the code
that loads eceval scans and patches that list, so it uses other list operations.
I had to revert after going south in a bad way.
Perhaps I missed some way to automate the transformation, a macro, but that's a
deeper rabbit hole (my scheme macro-fu is too old).
So I'm stuck. Nothing easy or recommended works. I'd like to either (1) know a scheme implementation that will run this code (2) some way I can implement set-car! and set-cdr! in racket (3) some other kind of work around (4) or maybe I just made a stupid mistake that one of you kind people will easily fix.
I tried (by either running racket directly or running it via DrRacket)
#lang sicp
(define foo '(a b))
(set-cdr! foo '(c))
foo
and it outputs (a c).
This also works:
#lang r5rs
(define foo '(a b))
(set-cdr! foo '(c))
(display foo)
To answer your question regarding the implementation of SICP (which I am currently maintaining), you are correct that (prefix-in r5rs: r5rs) will import set-cdr!.
Update: I just installed Geiser and now experienced the same problem that you did when I C-c C-b. However, C-c C-a works as expected.
Personally, I would use racket-mode instead of Geiser.
Mit-scheme will load the eceval compiler from the code drop mentioned in the question. On Ubuntu, mit-scheme loads with sudo apt-install mit-scheme. The geiser package of emacs finds mit via run-mit. The problem is solved.
I'm trying to use syntax parameters in order to inject new syntax where I need it to be injected. The result of this is then used in other syntax.
However, it's not working as I expect it to. Here's a minimal working example:
(require racket/stxparam)
(require (for-syntax racket/stxparam))
;; declare parameter to be replaced with code
(define-syntax-parameter placeholder
(lambda (stx)
(raise-syntax-error
(syntax-e stx)
"can only be used inside declare-many-commands")))
;; this is just to print what 'arg' looks like
(define-syntax (print-syntax stx)
(syntax-case stx ()
[(_ arg)
#'(displayln 'arg)]))
;; this is the top-level entity invoked to produce many commands
(define-syntax-rule (declare-many-commands cmds)
(begin
(let ([X 10])
(syntax-parameterize
([placeholder (make-rename-transformer #'X)])
cmds))
(let ([X 20])
(syntax-parameterize
([placeholder (make-rename-transformer #'X)])
cmds))))
(declare-many-commands
(print-syntax placeholder))
What I would like to get as result when running this is:
10
20
but what I get is:
placeholder
placeholder
EDIT:
Posted a new question to refine the problem: Injecting syntax at compile time using Racket's syntax parameters?
The problem here is that your print-syntax macro quotes its input, and inputs to macro transformers are unexpanded syntax. This means that the expansion of (print-syntax placeholder) will always be (displayln 'placeholder), and no macroexpansion ever occurs under quote, so the placeholder binding in scope is irrelevant.
If you want to use the syntax parameter, you need to actually produce a reference to the placeholder binding. In this case, you just need to remove the use of quote. You could change print-syntax to (displayln arg), but at that point, there’s really no reason for print-syntax to be a macro, since it’s equivalent to the displayln function. Just use that instead:
(declare-many-commands
(displayln placeholder))
This will print 10 and 20 as you expect.
It’s possible you really do want the quote, and I don’t understand your question. In that case, though, I think it’s difficult for me to understand what you’re getting at without some additional context.
I'm currently learning Scheme (using Racket), but one of the challenges I'm coming upon is trying to execute the following bit of code, which is meant to execute Racket code from user input using eval:
(display (eval (read)))
Here's some of the weird behavior I've observed so far:
(display (eval (read))) in the definition window prompts for keyboard input, as expected, when the definitions are run. However, providing the input
((lambda (x) (+ x 1)) 1)
gives the error
?: function application is not allowed;
no #%app syntax transformer is bound in: ((lambda (x) (+ x 1)) 1)
On the other hand, using (display ((eval (read)) 1)) and providing input
(lambda (x) (+ x 1))
returns the error
lambda: unbound identifier;
also, no #%app syntax transformer is bound in: lambda
However, running (display (eval (read))) and providing ((lambda (x) (+ x 1)) 1) in the console pane, as opposed to the definitions pane, prints out 2, as expected.
What is the reason for this behavior?
It looks like you don't have the namespace set up. If you're running (eval (read)) within a file, it doesn't work because the current-namespace is set to an empty namespace by default. You can set up a namespace with racket/base in it by doing (current-namespace (make-base-namespace)) first:
#lang racket
(current-namespace (make-base-namespace))
(println (eval (read)))
Running this program and giving it the input ((lambda (x) (+ x 1)) 1) results in it printing 2.
The reason it worked in the interactions window (item 3 of your weird-behavior list), is that in the interactions window, the current-namespace parameter is set to the namespace of the file.
This is not true for the definitions window, the main program, so you have to set the current-namespace yourself, or pass a namespace in as a second argument to eval:
#lang racket
(define ns (make-base-namespace))
(println (eval (read) ns))
Racket, the software package, has support for both R5RS and R6RS and will probably get support for R7RS. The software also has several non standard languages in its own Racket language family that has much in common with Scheme but is not Scheme. Alex has made an excellent answer for that language so I though I'd add information about Scheme since you write you're learning Scheme which is not the same as learning Racket when it comes some corner cases including eval.
eval is a procedure which has had breaking changes between the different Scheme reports since it became mandatory in R5RS. Here are some examples from different versions of the standard:
#!r6rs
(import (rnrs)
(rnrs eval))
(display (eval '((lambda (x) (+ x 1)) 1)
(environment '(rnrs))))
; ==> undefined, prints 2
The slightly older but still in common used R5RS:
#!r5rs
(display (eval '((lambda (x) (+ x 1)) 1)
(scheme-report-environment 5)))
; ==> undefined, prints 2
The to come R7RS which only has it's small version ratified so far:
#!r7rs
(import (scheme)
(scheme eval))
(display (eval '((lambda (x) (+ x 1)) 1)
(environment '(scheme))))
; ==> undefined, prints 2
I am trying to use the check-expect function in scheme but I keep being told its an unbound identifier for check-expect. Isn't check-expect a function I can use already? Below is my code:
#lang racket
(define contains (lambda (item list*)
(if (equal? list* '())
#f
(if (equal? item (car list*))
#t
(contains item (cdr list*))))))
(define z (list 1 2 3))
(define q (list 4 5 6))
(define p (list "apple" "orange" "carrot"))
(check-expect (contains 1 z) #t)
Old question, but answer for the googlers:
You can (require test-engine/racket-tests), which defines check-expect.
Note that, unlike BSL, you'll have to run the tests with (test).
check-expect is not technically built into scheme or Racket automatically.
Note that you are using #lang racket. That is the professional Racket language, and that language expects you to know and state explicitly what libraries to import. It will not auto-import them for you.
(Now, you could require a unit testing library; there is one that comes with the Racket standard library.)
But if you are just starting to learn programming, it makes much more sense to use one of the teaching languages within Racket.
For the code you're using above, I suspect you'll probably want this instead. Start DrRacket and choose "Beginner Student Language" from the "How to Design Programs" submenu in the "Language" menu.
See http://www.ccs.neu.edu/home/matthias/HtDP2e/prologue.html for more details.
I've managed to come up with this workaround:
At the top of the file (but after #lang racket) added a line
(require rackunit)
Instead of (check-expect) I've used
(check-equal? (member? "a" (list "b" "a")) #f )
Unlike in check-expect, tests must be added after the function definitions.
If the checks are successful, there is no output. Only when a tests fails, the output looks like this:
--------------------
FAILURE
name: check-equal?
actual: #f
expected: #t
expression: (check-equal? #f (member? "a" (list "b" "a")))
message: "test"
More Info: RackUnit documentation
I took a class using DrRacket and looked at the first assignment in Terminal (Mac).
The line in this file, automatically added by DrRacket, which made check-expect available is:
#reader(lib "htdp-beginner-reader.ss" "lang")((modname basic) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f)))
As a side note, I wanted to try a Racket program without DrRacket. Just to test, I decided to do (+ 1 2). To get it to work, my file looks like this:
#! /Applications/Racket\ v6.2.1/bin/racket
#lang racket
(+ 1 2)
I run it in Terminal like this:
racket test.rkt
I put this in .bash_profile:
alias racket='/Applications/Racket\ v6.2.1/bin/racket'