Racket lists incompatible with r6rs? - list

I'm writing a program in which i have to reuse code from one of my professors. My program is written in Racket and the code i want to reuse is written in r6rs.
When I want to test my program it always fails.
This is because I call a procedure with as argument a list (racket list), but that procedure is in the R6RS file. In the R6RS file there is (assert (list? argument)) , this is always false...
Here a simple example :
Racket code :
#lang racket
(require "test2.ss")
(define a (list 1 2 3))
(b a)
R6RS code :
#!r6rs
(library
(test)
(export b)
(import (rnrs base (6))
(rnrs control (6))
(rnrs lists (6))
(rnrs io simple (6)))
(define (b a)
(display "a is : ") (display a) (newline)
(display "list? : ") (display (list? a)) (newline)))
The list? test in the R6RS file is always false... even if I pass as argument a newly created list like in the above example.
How can I do the same as in the example above, so that the list? tests results true.
Thanks for your help!
EDIT : I could not find a r6rs test that results in true on a immutable list, but I found another way to resolve my problem (by passing a mutable list to the procedure).

Racket pairs are different from Scheme pairs since Racket pairs are immutable while Scheme pairs are not.
As far as I know, there is no way to check for Racket's immutable lists in pure RnRS Scheme. However, it is possible to use Scheme's mutable lists in Racket (though of course that isn't really recommended).
#lang racket
(require compatibility/mlist
"test2.ss")
(define a (mlist 1 2 3))
(b a)
Here's an excerpt from the documentation for compatibility/mlist:
This compatibility/mlist library provides support for mutable lists. Support is provided primarily to help porting Lisp/Scheme code to Racket.
Use of mutable lists for modern Racket code is strongly discouraged. Instead, consider using lists.
Still, if you need to interact with Scheme code, that's probably your only reasonable option.

This is just an addendum to Alexis King's answer (code examples can't be in comments). Since the r6rs language (as implemented in Racket) uses mutable lists, and all racket libraries expect immutable lists, you can't reuse the r6rs code as-is. The fastest way to reuse the code is to port it to the #lang racket language.
Change the language, remove the import statement, and then fix each error one at a time.
#lang racket
(define (b a)
(display "a is : ") (display a) (newline)
(display "list? : ") (display (list? a)) (newline)))

When you say your code is written in Racket. Do you mean Racket, the software, or #!racket, one of the multiple compatible languages that Racket (the software) supports?
Since your library is written in #!r6rs, you either need to port it to a #!racket module or you main program can be written in #!r6rs and you can use the library as is. A third option is to make mutable lists to pass to the library function and convert back but or ban lists all togerther, but I find this option somewhat suboptimal.
To do full #!r6rs you need to install your library like this:
plt-r6rs --force --install ./test.sls
I assume test.sls is in the current directory. You'll get a confirmation. you need not restart DrRacket. (Force is not needed, but it will overwrite an earlier version.) Then you just change your code to be Scheme code:
#!r6rs
(import (rnrs)
(test))
(define a (list 1 2 3))
(b a) ; #<void> (and prints stuff to stdout)
Hit [Run] in DrRacket and see the magic!

Related

Can one apply a macro to an argument list?

My goal is to be able to apply a macro to an argument list in the same way the apply primitive procedure applies a procedure to an argument list.
The list will already be evaluated at the time of application of the macro, there is no way around that and that’s fine; I am wondering if there is any way to programmatically “splice” the list into the macro application (in the same sense as with unquote-splicing). The difficulty resides in that one cannot pass the macro identifier as an argument.
One use case would be
(apply and list)
which would be equivalent to
(not (memq #f list))
to see if there is a #f in list.
Preferably this would be R7RS conformant.
One sort of hacky way would be (as suggested on reddit)
(eval (cons 'and list))
but this is not R7RS conformant, as eval must take an environment argument and it seems to me the standard doesn’t specify how to snatch the environment in effect at the call to eval.
Another half solution is the following, which only works if the list is given directly as a parenthesized sequence of values:
(syntax-rules ()
((_ identifier (val ...))
(identifier val ...)))
I'm posting this as a partial answer I found to my own question, and I'll accept it in a few days if nothing new pops up.
The following works, but only if the macro to apply is contained in a library.
(import (scheme base)
(scheme eval)
(scheme write))
(define (apply-macro mac args . libs)
(eval (cons mac args)
(apply environment libs)))
(define list '(#f #t #t #t))
(display (apply-macro 'and list '(scheme base))) ; => #f
(display (apply-macro 'and (cdr list) '(scheme base))) ; => #t
You can't do that; macros apply to syntax, transforming code fragments into other code fragments, not to values.
Even if you could do it, it would not be equivalent to applying and, since all the elements of list would be evaluated.
For instance, if you define the non-terminating procedure,
(define (forever) (forever))
then (and #f (forever)) is #f, but (apply and (list #f (forever))) would not terminate.
You cannot do this without eval. You would need to implement a procedure version of AND.
The reason it's impossible is because macro expansion is one phase and evaluation is a later phase. The list is piece of dynamic data existing only in the later phase, so a macro cannot use that.

If there is no distinct between read, compile and runtime in Lisp, can someone give me some intuitive examples?

As I read blog Revenge of the nerds, It says (in what made Lisp different section):
The whole language there all the time. There is no real distinction between read-time, compile-time, and runtime. You can compile or run code while reading, read or run code while compiling, and read or compile code at runtime.
Running code at read-time lets users reprogram Lisp's syntax; running code at compile-time is the basis of macros; compiling at runtime is the basis of Lisp's use as an extension language in programs like Emacs; and reading at runtime enables programs to communicate using s-expressions, an idea recently reinvented as XML.
In order to understand this sentence, I draw a statechart diagram:
I have two questions:
how to understand to read at runtime enable programming to communicate using s-expression, an idea reinvented as XML
what can we do when compiling at read time or reading at compile time?
XML let you exchange data at runtime between programs (or between different invocations of the same program). The same goes for JSON, which is a subset of Javascript and a little closer to Lisp in spirit. However, Common Lisp gives more control over how the different steps are executed; as explained in the quotes, you can reuse the same tools as your Lisp environment instead of building a framework like other languages need to.
Basically, you print data to a file:
(with-open-file (out file :direction :output)
(write data :stream out :readably t))
... and you restore it later :
(with-open-file (in file) (read in))
You call that "serialization" or "marshalling" in other languages (and in fact, in some Lisp libraries).
The READ step can be customized: you can read data written in a custom syntax (JSON.parse accepts a reviver function, so it is a little bit similar; the Lisp reader works for normal code too). For example, the local-time library has a special syntax for dates that can be used to rebuild a date object from a stream.
In practice, this is a bit more complex because not all data has a simple readable form (how do you save a network connection?), but you can write forms that can restore the information when you load it (e.g. restore a connection). So Lisp allows you to customize READ and PRINT, with readtables and PRINT-OBJECT, but there is also LOAD-TIME-VALUE and MAKE-LOAD-FORM, which allows you to allocate objects and initialize them when loading code. All of this is already available in the language, but there are also libraries that make things even easier, like cl-conspack: you just store classes into files and load them back without having to define anything special (assuming you save all slots). This works well thanks to the meta-object protocol.
Common Lisp
READ is a function which reads s-expressions and returns Lisp data.
CL-USER> (read)
(defun example (n) (if (zerop n) 1 (* (example (1- n)) n))) ; <- input
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N))) ; <- output
The last result again:
CL-USER> *
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N)))
Setting the variable code to the last result.
CL-USER> (setf code *)
(DEFUN EXAMPLE (N) (IF (ZEROP N) 1 (* (EXAMPLE (1- N)) N)))
What is the third element?
CL-USER> (third code)
(N)
We can evaluate this list, since it looks like valid Lisp code:
CL-USER> (eval code)
EXAMPLE
The function EXAMPLE has been defined. Let's get the function object:
CL-USER> (function example)
#<interpreted function EXAMPLE 21ADA5B2>
It's an interpreted function. We use a Lisp interpreter.
Let's use the function by mapping it over a list:
CL-USER> (mapcar (function example) '(1 2 3 4 5))
(1 2 6 24 120)
Let's compile the function:
CL-USER> (compile 'example)
EXAMPLE
NIL
NIL
The function has been compiled successfully. The compiler has no warnings and the function should now run much faster.
Let's use it again:
CL-USER> (mapcar (function example) '(1 2 3 4 5))
(1 2 6 24 120)
This is the same result, but probably much faster computed.
Since it is now compiled, let's disassemble the function:
CL-USER> (disassemble #'example)
0 : #xE3E06A03 : mvn tmp1, #12288
4 : #xE18D6626 : orr tmp1, sp, tmp1, lsr #12
8 : #xE5166030 : ldr tmp1, [tmp1, #-48]
... and a lot more lines of ARM assembler machine code

Scheme task decomposition - global variable issues

So here is my problem (generalized to an abstract situation). It is generally an interpreter.
I have got a program that needs to parse an input list and according to its elements sequentially call some functions that need to modify variables. Functions are defined separately and chosen by (cond . Those 3 variables that I need to update contain information about current situation (exactly - robot position, maze and robot orientation). The result of previous function is used in the next function (i.e. the updated variables are used).
(define func-a ... )
(define func-b ... )
(define (main-func <maze> <orientation> <coordinates> <list with commands>)
;; here I parse the list and choose which function to call
;; output must contain (list <new-maze> <new-orientation> <new-coordinates>))
)
What scheme tools can I use to update those variables? I have considered several options:
use (define and then call set! (this is bad style cause it is not pure functional programming);
call functions from back to beginning (this won't work: I also have to check if movement is valid);
don't make those variables constant at all, try passing them as arguments to each function;
Is there any other proper way to do it?
You have to keep some state (as well as read a file), so there will not be a pure functional programming, and you have to accept some deviations.
The general approach is to keep the shared object as a local in some meta-function, say parse, and update it by calling those your function, say parse-one, parse-two, and so on.
Now you need a way to update them.
You can make them visible for parse-one and parse-two by defining them inside the scope:
(let ((state (make-state)))
(let ((parse-one (lambda () ...))
(parse-two (lambda () ...)))
....))
Or you use the return value:
(let ((state (make-state)))
...
(set! state (parse-one state))
...)
There is a third approach, called OOP. Define all of them in a single closure, so they can share some data:
(define (make-parser)
(let ((state (make-state))
(let (((parse-one (lambda () ...))
((parse-two (lambda () ...))
((get-state (lambda () state)))
(list parse-one parse-two get-state))))
(destructuring-bind (parse-one parse-two get-state) (make-parser)
...
(parse-one)
...
(get-state))
(destructuring-bind is just an easy way to destruct a list, see it's scheme implementation) But it seems to be a complicated version of the first.
Just because Scheme is considered a 'functional language' doesn't forbid you from using 'set!' - after all it exists in the language to be used. Thus there is nothing wrong with:
(define-record-type position (fields x y z))
(define robot-position (make-position 0.0 0.0 0.0))
(define update-robot-position (new-x new-y new-z)
(set! robot-position (make-position new-x new-y new-x)))
[I've chosen to define positions as invariant.]
You can chose another approach if you want but fundamentally the position of the robot changed and that change will be in your code is some fashion. Why not use the simplest, most straight-forward approach?

Possible to get R5RS code to work with SchemeUnit?

In a class I am taking we are using the old R5RS standard of Scheme to solve SICP assignments. I like to do test first development, so I figured a unit testing framework would be nice, and I chose SchemeUnit for writing the small tests.
This has worked fine so far, just testing primitives in the output (strings, numbers, ...), but I hit a road block when trying to test lists. It has probably something to do with differences in the Scheme dialect used to run the tests:
foo.scm: (define a-list (list 2))
foo-tests.scm: (check-equal? a-list (list 2))
Result when running the tests:
Unnamed test
FAILURE
name: check-equal?
location: tester.scm:22:3
actual: {2}
expected: (2)
To make the test suite run, I have to add "#lang scheme/base to the top of foo-tests.scm and require the schemeunit package. In foo.scm I need to have #lang r5rs and (#%provide (all-defined)) at the top.
I guess lists are somehow differently implemented in R5RS and "scheme/base". Any way to get them to work together? And why does it fail ({} vs ())?
Yes, as you've noticed, lists are implemented differently in #lang r5rs vs #lang scheme/base. If it's possible to write the tests in your foo-tests.scm in r5rs, that would help to eliminate the possible confusion.
You should be able to do this by having this at the top of your foo-tests.scm file.
#lang r5rs
(#%require schemeunit)
(#%require "foo.scm")
;; Now you can add your tests here:
(check-equal? a-list (list 1 2 3))
If the test suite is written in the same language, then the constructs --- and in particular, the representation for lists --- should match up. The test above should hopefully pass.
To elaborate on the difference between the r5rs lists and the one in #lang scheme (and #lang racket): Racket uses immutable cons pairs to represent lists. Immutable cons pairs do not support the set-car! and set-cdr! functions of r5rs, so it wouldn't be faithful to the standard for the #lang r5rs language to use the built-in immutable pairs. To support the r5rs standard, Racket includes a separate mutable pairs data type, and uses it consistently within r5rs. But it means that the standard pairs in Racket and the mutable pairs do not compare equally.

Creating an empty list in Racket

I'm teaching myself LISP with online text of Structure and Interpretation of Computer Programs, but it differs in small details with the Racket program I'm running to learn LISP on. For example, SICP says that the terminating element of any list is 'nil', but Racket doesn't support 'nil'. How do I create an empty list in Racket so I can test my own procedures?
The empty list is denoted '(). So you can create a list like
(cons 1 (cons 2 (cons 3 '())))
This produces the list
'(1 2 3)
Sean's answer is correct. However, if you want to be able to type nil, then that's easy too. Just run this once at the start of your session:
(define nil '())
In Racket the empty list is designated as either:
'()
or as:
null
I would say that null is probably the more idiomatic of the two, and it dovetails consistently with the predicate null?, which tests for the empty list.
See the docs.