Is there a way to disable function-hoisting in Racket? - racket

I'm using Racket to teach (functional) programming, and I really like the way features are disabled for beginnings students. One problem however I'm having with Racket is the fact that functions seem to be hoisted even in the most restricted version. Now is there a way to disable function hoisting in racket so that the following code would produce an error?
(define (f x)
(g x)
)
(check-expect (f 3) 3)
(define (g x)
x
)

This behavior is not caused by hoisting functions. It is caused by check-expect. You can think of check-expect as being "hoisted downwards."
If you replace check-expect with your own function, you get the normal error:
g is used here before its definition
For the program:
(define (my-check-expect actual expected) ....)
(define (f x)
(g x))
(my-check-expect (f 3) 3)
(define (g x)
x)
If you want the students to only write tests after they code, you can make a teachpack that provides a new version of check-expect.
However, this is a bad idea. The Design Recipe teaches students to write functional examples/tests before they code. This special behavior of check-expect is what allows them to do that.

Related

Lisp: TAGBODY issue

I am a beginner in LISP programming and I am unsure how to use tagbody in order to read numbers from the keyboard until I reach a negative number. I tried to find resources available online, however I was unsuccessful so far.
Any help would be much appreciated!
You do not. tagbody is a very low-level facility.
Use do or loop instead:
(loop for num = (read) while (plusp num) collect num)
PS. The compiler might macro-expand my code to a tagbody similar to the form in the other answer. In a way, tagbody is the "assembly" of Lisp :-)
A good way to approach TAGBODY and its friend PROG is to consider your algorithm as a finite state-machine. Your function tries to implement the following:
You could write the following to implement the state machine:
(PROG* (N (E (CONS NIL NIL)) (Q (CONS E E)))
READ-NUMBER
(SETQ N (READ))
(IF (MINUSP N)
(GO FINISH)
(GO COLLECT))
COLLECT
(RPLACD Q (CDR (RPLACD (CDR Q) (CONS N NIL))))
(GO READ-NUMBER)
FINISH
(RETURN (CDAR Q)))
I upcased all symbols and used CAR/CDAR/... because like TAGBODY/PROG, that belongs to a style of programming that fell out of fashion decades ago.
A large set of useful state-machines are already abstracted away by LOOP or other iterators. That being said, TAGBODY is still available and might be useful in rare occasions, hidden behind macros.
Graphviz source
digraph abc {
rankdir=LR
nodesep=1
R[label="READ NUMBER"]
C[label="COLLECT"]
F[label="FINISH", penwidth=2]
I[style=invis, width=0]
I -> R [penwidth=0, arrowhead="vee"]
R -> C [label="N ≥ 0"]
C -> R [label="TRUE"]
R -> F [label="N < 0"]
}

Runtime pattern matching in Racket

If Racket's match macro were a function I could do this:
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42]))
(on-user-input
(λ (user-input)
(define expr (get-form-from-user-input user-input)) ; expr could be '(+ 1 2), for example.
(apply match expr my-clauses)))
I think there are two very different ways to do this. One is to move my-clauses into macro world, and make a macro something like this (doesn't work):
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42]))
(define-syntax-rule (match-clauses expr)
(match expr my-clauses)) ; this is not the way it's done.
; "Macros that work together" discusses this ideas, right? I'll be reading that today.
(on-user-input
(λ (user-input)
(define expr (get-form-from-user-input user-input)) ; expr could be '(+ 1 2), for example.
(match-clauses expr)))
The alternative, which might be better in the end because it would allow me to change my-clauses at runtime, would be to somehow perform the pattern matching at runtime. Is there any way I can use match on runtime values?
In this question Ryan Culpepper says
It's not possible to create a function where the formal parameters and body are given as run-time values (S-expressions) without using eval.
So I guess I'd have to use eval, but the naive way won't work because match is a macro
(eval `(match ,expr ,#my-clauses) (current-namespace))
I got the desired result with the following voodoo from the guide
(define my-clauses '([(list'+ x y) (list '+ y x)]
[_ 42]))
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(eval `(match '(+ 1 2) ,#my-clauses) ns) ; '(+ 2 1)
Is the pattern matching happening at runtime now? Is it a bad idea?
To answer the first part of your question (assuming you don't necessarily need the match clauses to be supplied at runtime):
The key is to:
Define my-clauses for compile time ("for syntax").
Reference that correctly in the macro template.
So:
(begin-for-syntax
(define my-clauses (list '[(list '+ x y) (list '+ y x)]
'[_ 42])))
(define-syntax (match-clauses stx)
(syntax-case stx ()
[(_ expr) #`(match expr #,#my-clauses)]))
The pattern matching is happening at runtime in the last example.
One way to check is to look at the expansion:
> (syntax->datum
(expand '(eval `(match '(+ 1 2) ,#my-clauses) ns)))
'(#%app eval (#%app list* 'match ''(+ 1 2) my-clauses) ns)
Whether is a good idea...
Using eval is rather slow, so if you call it often it might be better to find another solution. If you haven't seen it already you might want to read "On eval in dynamic languages generally and in Racket specifically." on the Racket blog.
Thank you both very much, your answers gave me much food for thought. What I am trying to do is still not very well defined, but I seem to be learning a lot in the process, so that's good.
The original idea was to make an equation editor that is a hybrid between paredit and a computer algebra system. You enter an initial math s-expression, e.g. (+ x (* 2 y) (^ (- y x) 2). After that the program presents you with a list of step transformations that you would normally make by hand: substitute a variable, distribute, factor, etc. Like a CAS, but one step at a time. Performing a transformation would happen when the user presses the corresponding key combination, although one possibility is to just show a bunch of possible results, and let the user choose the new state of the expression amongst them. For UI charterm will do for now.
At first I thought I would have the transformations be clauses in a match expression, but now I think I'll make them functions that take and return s-expressions. The trouble with choosing compile time vs runtime is that I want the user to be able to add more transformations, and choose his own keybindings. That could mean that they write some code which I require, or they require mine, before the application is compiled, so it doesn't force me to use eval. But it may be best if I give the user a REPL so he has programmatic control of the expression and his interactions with it as well.
Anyway, today I got caught up reading about macros, evaluation contexts and phases. I'm liking racket more and more and I'm still to investigate about making languages... I will switch to tinkering mode now and see if I get some basic form of what I'm describing to work before my head explodes with new ideas.

Scheme macro triggered by keyword which is not the head of a list

Suppose I want to trigger a Scheme macro on something other than the first item in an s-expression. For example, suppose that I wanted to replace define with an infix-style :=, so that:
(a := 5) -> (define a 5)
((square x) := (* x x)) -> (define (square x) (* x x))
The actual transformation seems to be quite straightforward. The trick will be getting Scheme to find the := expressions and macro-expand them. I've thought about surrounding large sections of code that use the infix syntax with a standard macro, maybe: (with-infix-define expr1 expr2 ...), and having the standard macro walk through the expressions in its body and perform any necessary transformations. I know that if I take this approach, I'll have to be careful to avoid transforming lists that are actually supposed to be data, such as quoted lists, and certain sections of quasiquoted lists. An example of what I envision:
(with-infix-define
((make-adder n) := (lambda (m) (+ n m)))
((foo) :=
(add-3 := (make-adder 3))
(add-6 := (make-adder 6))
(let ((a 5) (b 6))
(+ (add-3 a) (add-6 b))))
(display (foo))
(display '(This := should not be transformed))
So, my question is two-fold:
If I take the with-infix-define route, do I have to watch out for any stumbling blocks other than quote and quasiquote?
I feel a bit like I'm reinventing the wheel. This type of code walk seems like exactly what standard macro expanding systems would have to do - the only difference is that they only look at the first item in a list when deciding whether or not to do any code transformation. Is there any way I can just piggyback on existing systems?
Before you continue with this, it's best to think things over thoroughly -- IME you'd often find that what you really want a reader-level handling of := as an infix syntax. That will of course mean that it's also infix in quotations etc, so it would seem bad for now, but again, my experience is that you end up realizing that it's better to do things consistently.
For completeness, I'll mention that in Racket there's a read-syntax hack for infix-like expressions: (x . define . 1) is read as (define x 1). (And as above, it works everywhere.)
Otherwise, your idea of a wrapping macro is pretty much the only thing you can do. This doesn't make it completely hopeless though, you might have a hook into your implementation's expander that can allow you to do such things -- for example, Racket has a special macro called #%module-begin that wraps a complete module body and #%top-interaction that wraps toplevel expressions on the REPL. (Both of these are added implicitly in the two contexts.) Here's an example (I'm using Racket's define-syntax-rule for simplicity):
#lang racket/base
(provide (except-out (all-from-out racket/base)
#%module-begin #%top-interaction)
(rename-out [my-module-begin #%module-begin]
[my-top-interaction #%top-interaction]))
(define-syntax infix-def
(syntax-rules (:= begin)
[(_ (begin E ...)) (begin (infix-def E) ...)]
[(_ (x := E ...)) (define x (infix-def E) ...)]
[(_ E) E]))
(define-syntax-rule (my-module-begin E ...)
(#%module-begin (infix-def E) ...))
(define-syntax-rule (my-top-interaction . E)
(#%top-interaction . (infix-def E)))
If I put this in a file called my-lang.rkt, I can now use it as follows:
#lang s-exp "my-lang.rkt"
(x := 10)
((fib n) :=
(done? := (<= n 1))
(if done? n (+ (fib (- n 1)) (fib (- n 2)))))
(fib x)
Yes, you need to deal with a bunch of things. Two examples in the above are handling begin expressions and handling function bodies. This is obviously a very partial list -- you'll also want bodies of lambda, let, etc. But this is still better than some blind massaging, since that's just not practical as you can't really tell in advance how some random piece of code will end up. As an easy example, consider this simple macro:
(define-syntax-rule (track E)
(begin (eprintf "Evaluating: ~s\n" 'E)
E))
(x := 1)
The upshot of this is that for a proper solution, you need some way to pre-expand the code, so that you can then scan it and deal with the few known core forms in your implmenetation.
Yes, all of this is repeating work that macro expanders do, but since you're changing how expansion works, there's no way around this. (To see why it's a fundamental change, consider something like (if := 1) -- is this a conditional expression or a definition? How do you decide which one takes precedence?) For this reason, for languages with such "cute syntax", a more popular approach is to read and parse the code into plain S-expressions, and then let the actual language implementation use plain functions and macros.
Redefining define is a little complicated. See #Eli's excellent explanation.
If on the other hand, you are content with := to use set! things are a little simpler.
Here is a small example:
#lang racket
(module assignment racket
(provide (rename-out [app #%app]))
(define-syntax (app stx)
(syntax-case stx (:=)
[(_ id := expr)
(identifier? #'id)
(syntax/loc stx (set! id expr))]
[(_ . more)
(syntax/loc stx (#%app . more))])))
(require 'assignment)
(define x 41)
(x := (+ x 1))
(displayln x)
To keep the example to a single file, I used submodules (available in the prerelease version of Racket).

Implenting simultaneous bindings

I'm writing a Lisp (code at GitHub) and I want to implement local bindings. Currently I have two syntaxes:
(let <var> <val> <expr>)
for binding a single variable or function, and
(with (<var1> <val1> ... <varN> <valN>) <expr>)
to bind multiple values at once.
At present, the bindings are evaluated sequentially, and each new function binding retains a copy of the environment it was defined in, so <var2> can refer to <var1> but not vice-versa.
I would like to modify the code so that when binding multiple values at once you effectively have simultaneous binding. For example, I would like to be able to write (this is a trivial example, but it should illustrate the idea):
(define (h y)
(with ((f x) (if (eq? x 0) #t (g (- x 1)))
(g x) (if (eq? x 0) #f (f (- x 1))))
(f y))
At the moment this code doesn't run - g closes over f, but not the other way around.
Is there a canonical way to implement simultaneous binding in Lisp?
In SICP there's a section on internal definitions which covers this subject. In particular, the exercises 4.16, 4.18, 4.19 tell you how to implement different strategies for achieving simultaneous definitions.
The syntax is a bit different, but the idea in the book boils down to transforming this code:
(lambda <vars>
(define u <e1>)
(define v <e2>)
<e3>)
Into this code:
(lambda <vars>
(let ((u '*unassigned*)
(v '*unassigned*))
(set! u <e1>)
(set! v <e2>)
<e3>))
The same idea applies to your with special form. Take a look at the linked book for more implementation details.
In (with (a (+ 2 2))) we are binding a to the value of the expression (+ 2 2), so a becomes 4. But in (with ((f x) (+ x x))) we are doing something else: we are binding f to a function. This is a syntactic sugar for (with (f (lambda (x) (+ x x)))).
To handle this situation, you have to process the bindings in two passes. First collect all the variables and create the environment which contains all of them. Then evaluate the initializing experssions and store their values in the corresponding variables. The evaluation of these expressions takes place in that environment, so every expression has visibility over all the variables. The initialization is done by assignment. The variables can be initially nil or have some trap value which blows up if they are accessed.

Is there a Scheme interpreter that uses Normal-order evaluation?

I've been slowly working my way though the exercises in Structure and Interpretation of Computer Programs. Section 1.1.5 talks about applicative vs. normal-order evaluation, and the topic has come up several times in the text afterward. Since the interpreter uses applicative-order evaluation, it's easy to just insert display debug statements in your code to see exactly how it works. It would help my understanding to be able to do the same thing for normal-order evaluation.
Does anyone know of a Scheme (or Lisp) interpreter that's implemented using normal-order evaluation instead of applicative-order?
Update:
Here's a short example modified from the one given in SICP. I'll define my own add procedure to print out the arguments, and use the square procedure from the book.
(define (add x y)
(display x)
(display y)
(newline)
(+ x y))
(define (square x) (* x x))
Now if I run the short program (square (add 1 2)) using applicative-order evaluation, the result of (add 1 2) will only be computed once then passed to the square procedure. The operands 12 should be printed once before the final result. We can just run this in an interpreter to verify that this is what happens.
> (square (add 1 2))
12
9
Using normal-order evaluation, though, the single operand (add 1 2) should be copied into the square procedure, which would evaluate as (* (add 1 2) (add 1 2)). The operands 12 should be printed twice before the final result.
I'd like to be able to run this in an interpreter that does normal-order evaluation to verify that this is indeed how it works.
Turns out Scheme actually comes with what is essentially a normal-order evaluator already. They're those fabled macros you've probably heard so much about, and we can rewrite the examples of sections 1.1.4--1.1.5 to use macro expansion in lieu of procedure application rather easily:
(define (print . items)
(for-each display items))
(define-macro (add x y)
`(begin (print "[ADD " ',x " " ',y "]")
(+ ,x ,y)))
(define-macro (mul x y)
`(begin (print "[MUL " ',x " " ',y "]")
(* ,x ,y)))
(define-macro (square x)
`(begin (print "[SQUARE " ',x "]")
(mul ,x ,x)))
(define-macro (sum-of-squares x y)
`(begin (print "[SUM-OF-SQUARES " ',x " " ',y "]")
(add (square ,x) (square ,y))))
(define-macro (f a)
`(begin (print "[F " ',a "]")
(sum-of-squares (add ,a 1) (mul ,a 2))))
Ignore the PRINTs, their logic is a little beyond where you're at in the text, but they're just a shorthand for lots of DISPLAYs. Actually, you would want to entirely forgo the tracing-by-printing in favor of using the system's macro-expansion function. but this varies with the implementation (e.g. in Ypsilon you would use (macro-expand '(f 5))).
If you load these definitions (with the caveat that DEFINE-MACRO is non-standard, but that shouldn't be a problem in practice since most Schemes provide it), then evaluating (f 5) like the book does will print out (of course I prettied it up a little):
[F 5]
[SUM-OF-SQUARES (add 5 1) (mul 5 2)]
[ADD (square (add 5 1)) (square (mul 5 2))]
[SQUARE (add 5 1)]
[MUL (add 5 1) (add 5 1)]
[ADD 5 1]
[ADD 5 1]
[SQUARE (mul 5 2)]
[MUL (mul 5 2) (mul 5 2)]
[MUL 5 2]
[MUL 5 2]
136
Which is more or less what the book illustrates the process should be.
Writing these sorts of macros is basically like writing a normal procedure, except that
Instead of DEFINE, you use DEFINE-MACRO.
There is no implicit BEGIN over the body, so you need to supply your own if you have multiple expressions.
The entire body expression is prefixed with a grave accent.
All instances of the parameters are prefixed with a comma.
That's Writing Scheme Macros 101.
Now all in all, this is a little silly to spring macros on someone on just the first chapter of SICP. But if you say you're having an inordinate amount of difficulty modifying Racket to do what you want (and then there are those not using Racket at all), then here's an alternative.
Racket has a lazy language. It's better than just an interpreter, since you can write programs that are made of plain racket modules and lazy ones.
As for debugging using printouts -- you can do that in this lazy language, and you get something similar to unsafe IO in Haskell. This can still be confusing sometimes though. (And if you wanted an interpreter to plug printouts into it, it would also be confusing, because it follows the lazy evaluation...)