How to print user-defined environment in scheme? - scheme

In general I want write code in REPL and sometimes save all defined by myself symbols to file.
For example - after typing in REPL:
]=> (define (square x) (* x x))
]=> (define sizes '(5 10 15))
I need to call something to receive a list of previously defined objects.
In this case it can be represented in this way:
]=> (define get-user-defined-environment
(list (list 'sizes sizes) (list 'square square)))
To be able then call something like this:
]=> (map
(lambda (lst) (begin
(display "(define ")
(pp (first lst))
(pp (second lst))
(display ")\n\n")))
get-user-defined-environment)
(define sizes
(5 10 15)
)
(define square
(named-lambda (square x)
(* x x))
)
And, maybe, save output to file somehow.
So, what could be this get-user-defined-environment ?

There isn't something in standard Scheme that lets you record the environment. You can however define your own define-like syntax that does it for you.
> (define *env* '())
> (define-syntax def&rec
(syntax-rules ()
((_ name init)
(define name
(let ((value init))
(set! *env* (cons (cons 'name value) *env*))
value)))))
> (def&rec foo 1)
> (def&rec bar (lambda (x) x))
> *env*
((bar . #<procedure value>) (foo . 1))
If you intend to write this to a file, like with the expectation of reading it back in, you will want to record the init form, not value in the syntax above. Here is another syntactic form to record the init:
> (define-syntax def&rec2
(syntax-rules ()
((_ name init)
(define name
(let ((value init))
(set! *env* (cons (list 'name value 'init) *env*))
value)))))
> (def&rec2 equal-to (lambda (x) (lambda (y) (equal? x y))))
> *env*
((equal-to #<procedure value>
(lambda (x) (lambda (y) (equal? x y))))
(bar . #<procedure value>) (foo . 1))

Thanks to uselpa pointed to How can find all functions and bounded symbols in an "environment"
(environment-bound-names (the-environment)) - returns a list of user-defined names.
Then (environment-lookup (the-environment) name) - returns value of a name in current environment.
Here is the way:
]=> (define (p1 name env) (begin (display "(define ") (pp name) (pp (environment-lookup env name)) (display ")\n\n")))
]=> (define (p2 lst env) (for-each (lambda (name) (p1 name env)) lst))
]=> (p2 (reverse (environment-bound-names (the-environment))) (the-environment))
(define p1
(named-lambda (p1 name env)
(display "(define ")
(pp name)
(pp (environment-lookup env name))
(display ")\n\n"))
)
(define p2
(named-lambda (p2 lst env)
(for-each (lambda (name) (p1 name env)) lst))
)

Related

Unusual Scheme `let` binding, what is `f`?

In "The Scheme Programming Language 4th Edition" section 3.3 Continuations the following example is given:
(define product
(lambda (ls)
(call/cc
(lambda (break)
(let f ([ls ls])
(cond
[(null? ls) 1]
[(= (car ls) 0) (break 0)]
[else (* (car ls) (f (cdr ls)))]))))))
I can confirm it works in chezscheme as written:
> (product '(1 2 3 4 5))
120
What is 'f' in the above let? Why is the given ls being assigned to itself? It doesn't seem to match what I understand about (let ...) as described in 4.4 local binding:
syntax: (let ((var expr) ...) body1 body2 ...)
If 'f' is being defined here I would expect it inside parenthesis/square brackets:
(let ([f some-value]) ...)
This is 'named let', and it's a syntactic convenience.
(let f ([x y] ...)
...
(f ...)
...)
is more-or-less equivalent to
(letrec ([f (λ (x ...)
...
(f ...)
...)])
(f y ...))
or, in suitable contexts, to a local define followed by a call:
(define (outer ...)
(let inner ([x y] ...)
...
(inner ...)
...))
is more-or-less equivalent to
(define (outer ...)
(define (inner x ...)
...
(inner ...)
...)
(inner y ...))
The nice thing about named let is that it puts the definition and the initial call of the local function in the same place.
Cavemen like me who use CL sometimes use macros like binding, below, to implement this (note this is not production code: all its error messages are obscure jokes):
(defmacro binding (name/bindings &body bindings/decls/forms)
;; let / named let
(typecase name/bindings
(list
`(let ,name/bindings ,#bindings/decls/forms))
(symbol
(unless (not (null bindings/decls/forms))
(error "a syntax"))
(destructuring-bind (bindings . decls/forms) bindings/decls/forms
(unless (listp bindings)
(error "another syntax"))
(unless (listp decls/forms)
(error "yet another syntax"))
(multiple-value-bind (args inits)
(loop for binding in bindings
do (unless (and (listp binding)
(= (length binding) 2)
(symbolp (first binding)))
(error "a more subtle syntax"))
collect (first binding) into args
collect (second binding) into inits
finally (return (values args inits)))
`(labels ((,name/bindings ,args
,#decls/forms))
(,name/bindings ,#inits)))))
(t
(error "yet a different syntax"))))
f is bound to a procedure that has the body of let as a body and ls as a parameter.
http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_sec_11.16
Think of this procedure:
(define (sum lst)
(define (helper lst acc)
(if (null? lst)
acc
(helper (cdr lst)
(+ (car lst) acc))))
(helper lst 0))
(sum '(1 2 3)) ; ==> 6
We can use named let instead of defining a local procedure and then use it like this:
(define (sum lst-arg)
(let helper ((lst lst-arg) (acc 0))
(if (null? lst)
acc
(helper (cdr lst)
(+ (car lst) acc)))))
Those are the exact same code with the exception of some duplicate naming situations. lst-arg can have the same name lst and it is never the same as lst inside the let.
Named let is easy to grasp. call/ccusually takes some maturing. I didn't get call/cc before I started creating my own implementations.

Modifying the interpreter in Scheme

I'm totally new in Scheme and interpreters. My job is modifying the following code. If I run
(run "sub1(12,2,3,4)")
in Drracket, it returns 11. I need to modify the interpreter so that it behaves correctly for a single numeric argument, but returns 0 otherwise (that is, whenever the number of arguments is different from 1, or the argument is of incompatible type)
I understand different modules of the code, but I'm totally confused how to modify it. It would be great if you can help me or give me a pointer to some similar things.
#lang eopl
;;;;;;;;;;;;;;;; top level and tests ;;;;;;;;;;;;;;;;
(define run
(lambda (string)
(eval-program (scan&parse string))))
;; needed for testing
(define equal-external-reps? equal?)
;;;;;;;;;;;;;;;; grammatical specification ;;;;;;;;;;;;;;;;
(define the-lexical-spec
'((whitespace (whitespace) skip)
(comment ("%" (arbno (not #\newline))) skip)
(identifier
(letter (arbno (or letter digit "_" "-" "?")))
symbol)
(number (digit (arbno digit)) number)))
(define the-grammar
'((program (expression) a-program)
(expression (number) lit-exp)
(expression (identifier) var-exp)
(expression
(primitive "(" (separated-list expression ",") ")")
primapp-exp)
(expression
("if" expression "then" expression "else" expression)
if-exp)
(expression
("let" (arbno identifier "=" expression) "in" expression)
let-exp)
(expression
("proc" "(" (separated-list identifier ",") ")" expression)
proc-exp)
(expression
("(" expression (arbno expression) ")")
app-exp)
(expression
("begin" expression (arbno ";" expression) "end")
begin-exp)
(primitive ("+") add-prim)
(primitive ("-") subtract-prim)
(primitive ("*") mult-prim)
(primitive ("add1") incr-prim)
(primitive ("sub1") decr-prim)
(primitive ("zero?") zero-test-prim)
))
(sllgen:make-define-datatypes the-lexical-spec the-grammar)
(define show-the-datatypes
(lambda () (sllgen:list-define-datatypes the-lexical-spec the-grammar)))
(define scan&parse
(sllgen:make-string-parser the-lexical-spec the-grammar))
(define just-scan
(sllgen:make-string-scanner the-lexical-spec the-grammar))
;;;;;;;;;;;;;;;; the interpreter ;;;;;;;;;;;;;;;;
(define eval-program
(lambda (pgm)
(cases program pgm
(a-program (body)
(eval-expression body (init-env))))))
(define eval-expression
(lambda (exp env)
(cases expression exp
(lit-exp (datum) datum)
(var-exp (id) (apply-env env id))
(primapp-exp (prim rands)
(let ((args (eval-rands rands env)))
(apply-primitive prim args)))
(if-exp (test-exp true-exp false-exp) ;\new4
(if (true-value? (eval-expression test-exp env))
(eval-expression true-exp env)
(eval-expression false-exp env)))
(begin-exp (exp1 exps)
(let loop ((acc (eval-expression exp1 env))
(exps exps))
(if (null? exps) acc
(loop (eval-expression (car exps) env) (cdr exps)))))
(let-exp (ids rands body) ;\new3
(let ((args (eval-rands rands env)))
(eval-expression body (extend-env ids args env))))
(proc-exp (ids body) (closure ids body env)) ;\new1
(app-exp (rator rands) ;\new7
(let ((proc (eval-expression rator env))
(args (eval-rands rands env)))
(if (procval? proc)
(apply-procval proc args)
(eopl:error 'eval-expression
"Attempt to apply non-procedure ~s" proc))))
;&
(else (eopl:error 'eval-expression "Not here:~s" exp))
)))
;;;; Right now a prefix must appear earlier in the file.
(define eval-rands
(lambda (rands env)
(map (lambda (x) (eval-rand x env)) rands)))
(define eval-rand
(lambda (rand env)
(eval-expression rand env)))
(define apply-primitive
(lambda (prim args)
(cases primitive prim
(add-prim () (+ (car args) (cadr args)))
(subtract-prim () (- (car args) (cadr args)))
(mult-prim () (* (car args) (cadr args)))
(incr-prim () (+ (car args) 1))
(decr-prim () (- (car args) 1))
;&
(zero-test-prim () (if (zero? (car args)) 1 0))
)))
(define init-env
(lambda ()
(extend-env
'(i v x)
'(1 5 10)
(empty-env))))
;;;;;;;;;;;;;;;; booleans ;;;;;;;;;;;;;;;;
(define true-value?
(lambda (x)
(not (zero? x))))
;;;;;;;;;;;;;;;; procedures ;;;;;;;;;;;;;;;;
(define-datatype procval procval?
(closure
(ids (list-of symbol?))
(body expression?)
(env environment?)))
(define apply-procval
(lambda (proc args)
(cases procval proc
(closure (ids body env)
(eval-expression body (extend-env ids args env))))))
;;;;;;;;;;;;;;;; environments ;;;;;;;;;;;;;;;;
(define-datatype environment environment?
(empty-env-record)
(extended-env-record
(syms (list-of symbol?))
(vec vector?) ; can use this for anything.
(env environment?))
)
(define empty-env
(lambda ()
(empty-env-record)))
(define extend-env
(lambda (syms vals env)
(extended-env-record syms (list->vector vals) env)))
(define apply-env
(lambda (env sym)
(cases environment env
(empty-env-record ()
(eopl:error 'apply-env "No binding for ~s" sym))
(extended-env-record (syms vals env)
(let ((position (rib-find-position sym syms)))
(if (number? position)
(vector-ref vals position)
(apply-env env sym)))))))
(define rib-find-position
(lambda (sym los)
(list-find-position sym los)))
(define list-find-position
(lambda (sym los)
(list-index (lambda (sym1) (eqv? sym1 sym)) los)))
(define list-index
(lambda (pred ls)
(cond
((null? ls) #f)
((pred (car ls)) 0)
(else (let ((list-index-r (list-index pred (cdr ls))))
(if (number? list-index-r)
(+ list-index-r 1)
#f))))))
(define iota
(lambda (end)
(let loop ((next 0))
(if (>= next end) '()
(cons next (loop (+ 1 next)))))))
(define difference
(lambda (set1 set2)
(cond
((null? set1) '())
((memv (car set1) set2)
(difference (cdr set1) set2))
(else (cons (car set1) (difference (cdr set1) set2))))))
You could change as follows:
(define apply-primitive
[... part of code ...]
(decr-prim () (if (and (= (length args) 1) (number? (car args)))
(- (car args) 1)
0))
[... rest of code ...]
I assume the other primitives should be changed accordingly, this will only change sub1.

graphically plotting lisp code

Relating to a GP project I have a lot of auto-generated lisp snippets that can look basically like this:
(+ 2 (f1 (f2 x y) (f2 x y)))
In short: loads of one-liners.
How would one go about plotting this graphically into a function tree? Preferably by generating graphs in dot or something similar that can easily be shoved through graphviz so that i can render it into something like this:
+
/ \
/ \
2 f1
/ \
/ \
/ \
/ \
f2 f2
/ \ / \
/ \ / \
x y x y
How's this (in Scheme [Dr. Racket]):
(define (as-string elm)
(cond
((string? elm) (string-append "\\\"" elm "\\\""))
((number? elm) (number->string elm))
((symbol? elm) (symbol->string elm))
((null? elm) "*empty-list*")
(else (error "Unrecognized type"))))
(define (node-name-label names labels)
(apply append (map (lambda (a b)
(if (list? a)
(node-name-label a b)
(list (cons a b))))
names labels)))
(define (node-txt names labels)
(apply string-append (map (lambda (x)
(let ((name (car x)) (label (cdr x)))
(string-append name " [label=\"" (as-string label) "\"];\n")))
(node-name-label names labels))))
(define (graph-txt lst)
(apply string-append (map (lambda (x)
(let ((a (car x)) (b (cdr x)))
(string-append a " -- " b ";\n")))
(get-relationships lst))))
(define (declare-nodes lst (basename "node"))
(map (lambda (x n)
(if (and (list? x) (not (empty? x)))
(declare-nodes x (string-append basename "_" (number->string n)))
(string-append basename "_" (number->string n))))
lst
(range 0 (length lst))))
(define (get-relationships lst)
(if (< (length lst) 2)
null
(apply append (map (lambda (x)
(if (list? x)
(cons (cons (car lst) (car x)) (get-relationships x))
(list (cons (car lst) x))))
(cdr lst)))))
(define (range start end)
(if (>= start end)
'()
(cons start (range (+ 1 start) end))))
(define (get-graph code graph-title)
(let ((names (declare-nodes code)))
(string-append
"graph "
graph-title
" {\n"
(node-txt names code)
"\n"
(graph-txt names)
"}")))
Usage: (display (get-graph '(+ 2 (f1 (f2 () y) (f2 x y))) "simple_graph")) produces:
graph simple_graph {
node_0 [label="+"];
node_1 [label="2"];
node_2_0 [label="f1"];
node_2_1_0 [label="f2"];
node_2_1_1 [label="*empty-list*"];
node_2_1_2 [label="y"];
node_2_2_0 [label="f2"];
node_2_2_1 [label="x"];
node_2_2_2 [label="y"];
node_0 -- node_1;
node_0 -- node_2_0;
node_2_0 -- node_2_1_0;
node_2_1_0 -- node_2_1_1;
node_2_1_0 -- node_2_1_2;
node_2_0 -- node_2_2_0;
node_2_2_0 -- node_2_2_1;
node_2_2_0 -- node_2_2_2;
}
I made a quick&dirty perl script that does what i need. Placing it here in case someone else could use it:
Link: http://jarmund.net/stuff/lisp2svg.pl.txt
Example output: http://jarmund.net/graphs/lisp.svg
NB: You're not allowed to laugh at the ugly code, and it only handles the most basic things, so it might require some hacking to do anything more than what i need it for.

Improperly placed closed parenthesis in scheme function

I have the following scheme function:
(define get-ivars
(λ (ivars num)
(cond ((null? ivars) '())
(else
(append (list (car ivars) `(nth args ,num)) (list (get-ivars (cdr ivars) (+ num 1))))))))
That returns the following in a specific instance:
(x (nth args 1) (y (nth args 2) ()))
The problem is, I need it to return:
((x (nth args1)) (y (nth args 2)) ())
-the two closing parenthesis at the end should be after the (nth statements.
How would I go about getting this to work properly?
get-ivars caller:
(define gen-classes
(λ (classes)
(cond ((null? classes) '())
(else
(let* ((class (car classes)))
(eval
`(define ,(cadr class)
(λ (args)
(let (
,(get-ivars (cdr (cadddr class)) 1)
)
(eval
(let* ,(cdar (cddddr class))
(λ (method . args)
,(get-methods (cdadr (cddddr class)))
))))))))))))
That second (list ...) in your else clause is what's screwing you up. It's nesting each successive call deeper and deeper. The recursion will naturally create the list; you don't need to wrap it again.
Try:
(define get-ivars
(λ (ivars num)
(if (null? ivars) '()
(cons (list (car ivars) `(nth args ,num))
(get-ivars (cdr ivars) (+ num 1))))))
Regarding the get-ivars caller code, the parentheses surrounding the unquoted call to get-ivars are what's giving you the trouble you mention in the comments. With them, this code:
`(define ClassName
(lambda (args)
(let (,(get-ivars '(iVar1 iVar2 iVar3) 1))
;; your method-getting code
)))
Gives you this:
(define ClassName
(lambda (args)
(let (((iVar1 (nth args 1))
(iVar2 (nth args 2))
(iVar3 (nth args 3))))
;; method-getting code
)))
Which, as you can see, gives you an extra set of parentheses around the assignments in the let.
So you want to do this:
`(define ClassName
(lambda (args)
(let ,(get-ivars '(iVar1 iVar2 iVar3) 1)
;; your method-getting code
)))
get-ivars is returning a list of lists, which is exactly what you want for the assignments in the let, so you don't need to wrap or (as I had it earlier) splice it. Just use the unquote on its own, and the result is:
(define ClassName
(lambda (args)
(let ((iVar1 (nth args 1))
(iVar2 (nth args 2))
(iVar3 (nth args 3)))
;; method-getting code
)))
Which should do the trick.
Incidentally, I found it helpful to leave off the eval when I was playing around with this; one can then visually inspect the result to make sure its syntax is okay.
I haven't tried this, but I think this would work:
(define (get-ivars ivars num)
(if (null? ivars)
'()
(list (list (car ivars) `(nth args ,num))
(get-ivars (cdr ivars) (1+ num)))))

Scheme Formatting Help

I've been working on a project for school that takes functions from a class file and turns them into object/classes. The assignment is all about object oriented programming in scheme.
My problem however is that my code doesn't format right.
The output it gives me whenever I give it a file to pass in wraps the methods of the class in a list, making it so that the class never really gets declared. I can't for the life of me figure out how to get the parenthesis wrapping the method list to remove.
I would really appreciate any help.
Below is the output, the class file and the code,.
(define pointInstance
(let ((myx 1) (myy 2))
(lambda msg
(cond
(((eq? (car msg) getx) myx)
((eq? (car msg) gety) myy)
((eq? (car msg) setx) (set! myx x))
((eq? (car msg) show) (begin (display "[") (display myx) (display ",") (display myy) (display "]"))))))))
If you look at just after the cond you'll see how all those eq statements are contained in a list. I can't get this to work right unless they're not wrapped by that top level list.
;;;; PART1 --- A super-easy set of classes. Just models points and lines. Tests all of >the
;; basics of class behavior without touching on anything particularly complex.
(class pointInstance (parent:) (constructor_args:)
(ivars: (myx 1) (myy 2))
(methods:
(getx () myx)
(gety () myy)
(setx (x) (set! myx x))
(show () (begin (display "[") (display myx) (display ",") (display myy) (display "]")))
))
(require (lib "trace.ss"))
;; Continue reading until you hit the end of the file, all the while
;; building a list with the contents
(define load-file
(lambda (port)
(let ((rec (read port)))
(if (eof-object? rec)
'()
(cons rec (load-file port))))))
;; Open a port based on a file name using open-input-file
(define (load fname)
(let ((fport (open-input-file fname)))
(load-file fport)))
;(define lis (load "C:\\Users\\Logan\\Desktop\\simpletest.txt"))
;(define lis (load "C:\\Users\\Logan\\Desktop\\complextest.txt"))
(define lis (load "C:\\Users\\Logan\\Desktop\\pointinstance.txt"))
;(display (cdaddr (cdddar lis)))
(define makeMethodList
(lambda (listToMake retList)
;(display listToMake)
(cond
[(null? listToMake)
retList
;(display "The list passed in to parse was null")
]
[else
(makeMethodList (cdr listToMake) (append retList (list (getMethodLine listToMake))))
]
)
))
;(trace makeMethodList)
;this works provided you just pass in the function line
(define getMethodLine
(lambda (functionList)
`((eq? (car msg) ,(caar functionList)) ,(caddar functionList))))
(define load-classes
(lambda paramList
(cond
[(null? paramList) (display "Your parameters are null, man.")]
[(null? (car paramList))(display "Done creating class definitions.")]
[(not (null? (car paramList)))
(begin
(let* ((className (cadaar paramList))
(classInstanceVars (cdaddr (cddaar paramList)))
(classMethodList (cdr (cadddr (cddaar paramList))))
(desiredMethodList (makeMethodList classMethodList '()))
)
;(display "Classname: ")
;(display className)
;(newline)(newline)
;(display "Class Instance Vars: ")
;(display classInstanceVars)
;(newline)(newline)
;(display "Class Method List: ")
;(display classMethodList)
;(newline)
;(display "Desired Method List: ")
;(display desiredMethodList))
;(newline)(newline)
;----------------------------------------------------
;do not delete the below code!`
`(define ,className
(let ,classInstanceVars
(lambda msg
;return the function list here
(cond ,(makeMethodList classMethodList '())))
))
;---------------------------------------------------
))]
)
))
(load-classes lis)
;(load-classes lis)
;(load-classes-helper lis)
;(load-classes "simpletest.txt")
;(load-classes "complextest.txt")
;method list
;(display (cdr (cadddr (cddaar <class>))))
You have too many opening parenthesis in the 1st clause of the cond.
IE:
(((eq? (car msg) getx) myx)
^
Updated:
Are you looking for this?
(cond ,#(makeMethodList classMethodList '())
^^
Or you can do:
(cond . ,(makeMethodList classMethodList '())

Resources