DrRacket, R5RS and the error procedure - scheme

I love DrRacket IDE, but currently I'm building a pet project where I would like to be independent from it, meaning i'm commited to use only R5RS standard procedures.
The thing is, in DrRacket there's this procedure called "error" which i would like to continue using but I can't find it in the Standards.
What i would like to know is if there's a way to emulate that "error" procedure using only the Standards procedures so that the code is portable between different implementations of Scheme.
I've tried "display" but it doesn't seem to be quite what I want for that does not signal an error while outputting.

This is the implementation that our lecturer gave us:
;;; create binding for error
(define error #f)
;;; capture toplevel continuation
;;; assign a function to error, allowing a variable number of arguments to
;;; be passed
(call-with-current-continuation (lambda (k)
(set! error
(lambda error-arguments
(display ">>>> ERROR ")
(newline)
(k error-arguments)))
'done))

Well, according to this: http://srfi.schemers.org/srfi-23/srfi-23.html, the error procedure is pretty widely available, so I think you would be safe using that.

Related

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.

Splicing syntax parameterize disables Typed Racket type annotations

When I run the following, I get a type error as expected:
#lang typed/racket
(require racket/stxparam)
(define-syntax-parameter x #f)
(syntax-parameterize ([x #'foo])
(: n Number)
(define n "string")
'foo)
But when I use splicing-syntax-parameterize instead, suddenly I get no type errors
#lang typed/racket
(require racket/stxparam
racket/splicing)
(define-syntax-parameter x #f)
(splicing-syntax-parameterize ([x #'foo])
(: n Number)
(define n "string"))
Examining at the REPL shows that n has type String, despite the annotation.
The documentation for splicing-syntax-parameterize claims that it treats definitions in the same manner as begin:
Like syntax-parameterize, except that in a definition context, the body forms are spliced into the enclosing definition context (in the same way as for begin).
However, if I use begin instead of splicing-syntax-parameterize:
#lang typed/racket
(begin
(: n Number)
(define n "string"))
Then I do get a type error. Is there some reason splicing-syntax-parameterize strips away type annotations from definitions, but begin does not? I would hazard a guess it's because the splicing-syntax-parameterize is basing its behavior on the untyped begin form instead of the begin form from Typed Racket, and thus knows absolutely nothing about the : form. If that's the case, how can I work around this?
Yes, this is a bug. It turns out that splicing-syntax-parameterize has a somewhat strange expansion that doesn't play nicely with the way Typed Racket detects and installs type annotations.
I have written a fix for this bug, which you can find here. As expected, your original program now fails to typecheck. This fix should be available in Racket 6.1.1.8 or greater, so if you need this behavior, use a snapshot build or use the newest version of Typed Racket.
Otherwise, this should be included in the next Racket release.

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

In Scheme the purpose of (let ((cdr cdr))

I've been studying Scheme recently and come across a function that is defined in the following way:
(define remove!
(let ((null? null?)
(cdr cdr)
(eq? eq?))
(lambda ... function that uses null?, cdr, eq? ...)
What is the purpose of binding null? to null? or cdr to cdr, when these are built in functions that are available in a function definition without a let block?
In plain R5RS Scheme, there is no module system -- only the toplevel. Furthermore, the mentality is that everything can be modified, so you can "customize" the language any way you want. But without a module system this does not work well. For example, I write
(define (sub1 x) (- x 1))
in a library which you load -- and now you can redefine -:
(define - +) ; either this
(set! - +) ; or this
and now you unintentionally broke my library which relied on sub1 decrementing its input by one, and as a result your windows go up when you drag them down, or whatever.
The only way around this, which is used by several libraries, is to "grab" the relevant definition of the subtraction function, before someone can modify it:
(define sub1 (let ((- -)) (lambda (x) (- x 1))))
Now things will work "more fine", since you cannot modify the meaning of my sub1 function by changing -. (Except... if you modify it before you load my library...)
Anyway, as a result of this (and if you know that the - is the original one when the library is loaded), some compilers will detect this and see that the - call is always going to be the actual subtraction function, and therefore they will inline calls to it (and inlining a call to - can eventually result in assembly code for subtracting two numbers, so this is a big speed boost). But like I said in the above comment, this is more coincidental to the actual reason above.
Finally, R6RS (and several scheme implementations before that) has fixed this and added a library system, so there's no use for this trick: the sub1 code is safe as long as other code in its library is not redefining - in some way, and the compiler can safely optimize code based on this. No need for clever tricks.
That's a speed optimization. Local variable access is usually faster than global variables.

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