Racket REPL over TCP - scheme

I've built a rather complex application with Racket (formerly PLT Scheme) and would like to add a REPL for debugging purposes. I've tried to make it accessible over a TCP stream:
(define repl-server
(thread (lambda ()
(let ((listener (tcp-listen 8082 5 #t)))
(do () (#f)
(let-values (((in out) (tcp-accept listener)))
(thread (lambda ()
(let ((port-string (get-port-string in)))
(Try "debug-repl" #f
(begin
(file-stream-buffer-mode out 'line)
(display-and-log "Password: " out)
(flush-output out)
(when (string=? (read-line in) "whatever")
(log "Connect to REPL: " port-string))
(current-input-port in)
(current-output-port out)
(current-error-port out)
(read-eval-print-loop))
(close-input-port in)
(close-output-port out))))))))))))
(Try name result-if-exception form) is a macro providing basic exception handling, (log ...) and (display-and-log ...) do what they sound like.
Now if I access the REPL, I can't even evaluate constants, as I keep getting the error compile: unbound identifier (and no #%app syntax transformer is bound) at: #%top-interaction. How can I make this REPL work? And how can I access values defined before starting the REPL server?

You're using read-eval-print-loop, which is essentially the same as using eval, and therefore suffers from the same kind of problems. See the relevant Guide section for a detailed explanation. It's best to read that completely, but the answers that you're looking for are either what the "Namespaces" section describes, or the "Namespaces and Modules" section -- the first is if you want a toplevel kind of a namespace, and the second is if you want a namespace that corresponds to the actual file that the code appears in. (The first is usually better -- for example, if you use the second then repl-server is itself available for the REPL user, making it a questionable feature...)
Here's how it would look like:
...
(thread (lambda ()
(parameterize ([current-namespace (make-base-namespace)])
...same code...)))
...
and for the second one, define an anchor and use namespace-anchor->namespace as the last example on that page shows.
[BTW, see also the run-server thing, it's a little old, but can still be useful.]

Related

SICP Ch5 eceval compiler in Racket: set-cdr! into quoted list (not a dup)

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.

SCHEME - printf as a debug technique?

Is the printf command a sensible way to attempt a debug or other techinuqes would be faster and/or more precise?
(Assume that I'm using Racket or other dialects that allow printf).
First off. Scheme (R7RS, R6RS, R5RS) doesn't have printf. There is display and SRFI-28 format. Because of this I'll just read printf as print statement which again could mean you're just using display.
The correct answer is that your code should be made into small procedures that can be unit tested easily. If you do that you'll never need either a debugger or printing out debug info ever again.
Usually Scheme uses expressions and it's not always easy to just add a print statement without having to wrap it and the following statement in a begin. Because of that you may introduce bugs when you add and, even worse, remove debug information from your code. eg.
(if (test arg)
(call-something (car arg))
(call-something-else (cdr arg))
So how much would you have to change in order to print the result of (test arg) without altering the course of the code and how easy would it be to remove that without introducing a new bug? If I really wanted to print out debug info I would have made a macro:
(define-syntax dbg
(syntax-rules ()
((_ . rest)
(let ((expr 'rest)
(res rest))
(display (list expr '=> res))
res))))
Now you could just prefix dbg where you want to inspect:
(if (dbg test arg)
(call-something (car arg))
(call-something-else (cdr arg))
Imagine that the result og (test arg) is 5, then you'll get ((test arg) => 5) out without altering the result to if.
If you happen to use DrRacket it's very simple to use the very good debugger and macro stepper which they have. With it you'll just set a break point and run towards the interesting parts and step through as you see the values every step calculates. There are probably some other IDEs as well but I stopped looking after I found racket. Even when using DrRacket nothing is keeping you from using a different implementation in production, like Ikarus, provided that you write in one of the Scheme reports and not something implementation specific.
Be careful! People who are too comfortable with debuggers tend to make long procedures that look more like FORTRAN than Scheme. The best is to write programs as if you didn't have any means of debugging, use the debugger when you feel the need and refactor your code if you find yourself in the debugger all the time.

What exactly is the purpose of syntax objects in scheme?

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.

scheme call/cc for handling errors

I have a Scheme application that accepts some user input, computes, and gives some output. I would like to make it more robust by enabling some kind of error handling and a way to exit smoothly. Call with current continuation seems to be the thing to fill this gap here, but I'm not quite sure how to go about implementing it.
As of now, if the user enters some non-valid input, the program will crash and exit. I would simply like to keep the user in the application and give an error message instead. Here is an outline of my method, but I'm not sure where to implement it so that if an error occurs that would normally crash the system, just gives an error and keeps them in the program.
(define (handle_err)
(call/cc
(lambda (a)
(display "exception handled: a"))))
I would also like a clean exit from the program. That is, not a crash exit, nor a break. I would like the user to type "leave", have the program close and return to the interpreter. My outline looks much like the above, but it doesn't have the user leave the program, it just takes him back to the input prompt.
Any ideas are appreciated.
Yes, call/cc can handle this kind of transfer of control. One problem here is that the call/cc corresponds to the "try/catch" in this example, not to the "throw".
A bigger problem, though, is that you don't have any nice way in r5rs to get control when an error occurs.
This is really just a symptom of an even bigger problem, which is that various different Scheme implementations have solved this problem in different ways.
Personally, I would strongly urge you to take a look at Racket; it's supported on many versions of Linux, lives in many standard distros, and handles this really nicely:
#lang racket
(with-handlers ([exn:fail?
(lambda (exn)
(display "oh noes! An exception occurred!"))])
(try-something-dangerous))
(define (try-something-dangerous)
(/ 1 0))
Actually, I would recommend Racket even if you want to write r5rs programs; you can just begin your programs with
#lang r5rs
... to get full r5rs compliance.
Well, you make look at this approach
(define-syntax try
(syntax-rules ()
((_ handler throw chunk)
(call/cc (lambda (catch)
(let ((throw (lambda (exc) (catch (handler exc)))))
chunk))))))
(define (div p q)
(try
;; Error processing
(lambda (error) (printf "Error: ~s~n" error) error)
;; Error my be thrown with keyword "throw"
throw
;;Actual code to run
(if (= q 0)
;; Oh noes, error!
(throw "Division by zero")
;; All ok, do the work
(/ p q))))
(printf "1/0: ~s~n" (div 1 0))
(printf "1/2: ~s~n" (div 1 2))
The "throw" is used to capture name for throw function (this is need because of hygiene).

Why doesn't Scheme support first class environments?

I've been reading through SICP (Structure and Interpration of Computer Programs) and was really excited to discover this wonderful special form: "make-environment", which they demonstrate to use in combination with eval as a way of writing modular code (excerpt from section 4.3 on "packages"):
(define scientific-library
(make-environment
...
(define (square-root x)
...)))
They then demonstrate how it works with
((eval 'square-root scientific-library) 4)
In their example, they then go on to demonstrate exactly the usage that I would want - an elegant, minimalist way of doing the "OO" style in scheme... They "cons" together a "type", which is actually what was returned by the "make-environment" special form (i.e. the vtable), and an arg ("the state")...
I was so excited because this is exactly what I've been looking for as a way to do polymorphic dispatch "by symbol" in Scheme without having to write lots of explicit code or macros.
i.e. I want to create an "object" that has, say, two functions, that I call in different contexts... but I don't want to refer to them by "car" and "cdr", I want to both declare and evaluate them by their symbolic names.
Anyway, when I read this I couldn't wait to get home and try it.
Imagine my disappointment then when I experienced the following in both PLT Scheme and Chez Scheme:
> (make-environment (define x 3))
Error: invalid context for definition (define x 3).
> (make-environment)
Error: variable make-environment is not bound.
What happened to "make-environment" as referenced in SICP? It all seemed so elegant, and exactly what I want, yet it doesn't seem to be supported in any modern Scheme interpreters?
What's the rationale? Is it simply that "make-environment" has a different name?
More information found later
I took at look at the online version:
https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-28.html#%_sec_4.3
I was reading was the first edition of SICP. The second edition appears to have replaced the discussion on packages with a section on non-deterministic programming and the "amp" operator.
After more digging around I discovered this informative thread on newsnet:
"The R5RS EVAL and environment specifiers are a compromise between
those who profoundly dislike first-class environments and want a
restricted EVAL, and those who can not accept/understand EVAL without
a second argument that is an environment."
Also, found this "work-around":
(define-syntax make-environment
(syntax-rules ()
((_ definition ...)
(let ((environment (scheme-report-environment 5)))
(eval '(begin definition
...)
environment)
environment))))
(define arctic
(make-environment
(define animal 'polarbaer)))
(taken from this)
However, I ended up adopting a "message passing" style kinda of like the first guy suggested - I return an alist of functions, and have a generic "send" method for invoking a particular function by name... i.e something like this
(define multiply
(list
(cons 'differentiate (...))
(cons 'evaluate (lambda (args) (apply * args)))))
(define lookup
(lambda (name dict)
(cdr (assoc name dict))))
; Lookup the method on the object and invoke it
(define send
(lambda (method arg args)
((lookup method arg) args)))
((send 'evaluate multiply) args)
I've been reading further and am aware that there's all of CLOS if I really wanted to adopt a fully OO style - but I think even above is somewhat overkill.
They wrote it like that because MIT Scheme does, in fact, have first-class environments, and presumably that's what the writers were planning to teach their class with (since the book was written at MIT).
Check out http://groups.csail.mit.edu/mac/projects/scheme/
However, I've noticed that MIT Scheme, while still somewhat actively developed, lacks many of the features that a really modern Scheme would have, like a foreign function interface or GUI support. You probably wouldn't want to use it for a serious software development project, at least not by itself.
Scheme has no first-class environments because of performance reasons. When Scheme was created, it wasn't the fastest language around due to nifty stuff like first-class functions, continuations, etc. Adding first-class environments would have crippled the performance even further. So it was a trade-off made in the early Scheme days.
Would a classical dispatcher function work? I think this is similar to what you're looking for.
(define (scientific-library f)
(define (scientific-square-root x) (some-scientific-square-root x))
(cond ((eq? f 'square-root) scientific-square-root)
(else (error "no such function" f))))
(define (fast-library f)
(define (fast-square-root x) (some-fast-square-root x))
(cond ((eq? f 'square-root) fast-square-root)
(else (error "no such function" f))))
((scientific-library 'square-root) 23)
((fast-library 'square-root) 23)
You could even combine the example scientific and fast libraries into one big dispatch method:
(define (library l f)
(define (scientific-library f)
...)
(define (fast-library f)
...)
(cond ((eq? l 'scientific) (scientific-library f))
((eq? l 'fast) (fast-library f))
(else (error "no such library" l))))
(library 'fast 'square-root)

Resources