I'm attempting to return a variable in the scope of a different environment.
What I have currently is
(define make-empty-env
(lambda()
(make-top-level-environment)
)
)
which creates a new environment when you call it from the interpreter
i.e. (define env (make-empty-env))
If I define the variable "a" as 15 in "env", my goal is to return this value through a function called from the user-initial-environment.
Something along the lines of
(apply-env env 'v) outputs -> value of variable v in scope of env.
v can be undefined in user-initial-environment but would still return a value if the variable exists in env.
I've tried:
(define apply-env
(lambda (env v)
(eval (+ v 0) env)
)
)
which doesn't work since I'm passing a symbol 'v when I call the function. My main problem is that I don't know how to pass a symbol and treat it like a variable in the function. This is for a homework and the prompt for the function is:
(apply-env env v)
Returns the value of variable v in environment env.
Here are some calls to apply-env:
In test-env, a = 1, b = 2
(apply-env test-env 'a)
1
(apply-env test-env 'b)
2
I'm relatively new to scheme so I'm probably missing some fundamental basics, any pointers or help would be very much appreciated.
As far as I know the design implementation for your environment variable is up to you. Since its a homework question I'm assuming that you can go about it any way you like (I assume).
So lets say you want to make your environment variable as a that is a list of list of 2 elements.
env -> ((var1,val1),(var2,val2),......,(varn.valn))
E.g.
env -> ((a,1),(b,2),(c,3))
Now when you want to "create" your environment initially, you simply want to call a function which returns the initial environment which is empty. Now our environment variable env is just an empty list '(). You could make a function like this
(define (make-empty-env)
(lambda ()
'()
)
)
Now to add, remove and update variables in env you can implement function like car and cdr and in-env? for the underlying data structure
;;; cdr like function for env
(define (cdr-env env)
(cdr env)
)
;;; car like function for env
(define (car-env)
(list (car env))
)
;;; Returns boolean for v in env
(define (in-env? env)
(cond
((null? env) ; If env is empty then v doesnt exist in env
#f
)
((equal? v (car (car env))) ; If first element of the first list in env matches with v
#t
)
(else ; Recursive step to find if v is in the remaining enviornment env
(in-env? v (cdr env))
)
)
)
Using these functions you can relatively easily implement your insertion, retrieval and updation functions for env.
;;; Update the value variable v to val in env. This function assumes that you are calling it in the insert-env function
(define (update-env v val env)
(cond
((null? env)
'()
)
((equal? v (car (car env)))
(append (cdr env) (list (list v val)))
)
(else
(append
(update-env v val (cdr env))
(list (list (car (car env)) (car (cdr (car env)))))
)
)
)
)
;;; add a variable-value pair (v,val) to env, also checks if variable already exists in pair. If so then updates it
(define (insert-env v val env)
(cond
((in-env? v env)
(update-env v val env)
)
(else ; Add to env the 2 element list (v val)
(append env (list (list v val)))
)
)
)
;;; Gets the value of variable v or returns an error message
(define apply-env
(lambda (env v)
(cond
((null? env) ; If env is empty then no variablles exist for the name v
(error "appply-env: found empty enviroment")
)
((equal? (car (car env)) v) ; First element of the first list is v [matching var found in env]
(car (cdr (car env))) ; Second element of that list is value of v
)
(else ; Else look for v in the rest of the env list
(apply-env (cdr env) v)
)
)
)
)
NOTE:
Your implementations of functions like above for env will depend on how you choose to implement the data structure that will store your variable bindings in env
You can use any data structure you like. E.g. Binary tree. stack, queue, etc
Hope this helps!
The issue is that the addition isn't staged. Consider the following using quasiquotiation:
(define apply-env
(lambda (env v)
(eval `(+ ,v 0) env)
)
)
The quasiquotation is equivalent to (list '+ v 0).
Related
I have a Lisp program that's going through nested list and deleting elements that match the element passed through to the function. My issue is, if everything in one of the nested list is deleted, I need to print out () instead of NIL.
(defun del (x l &optional l0)
(cond ((null l) (reverse l0))
((if (atom x) (eq x (car l)) (remove (car l) x)) (del x (cdr l) l0))
(T (del x (cdr l) (cons (if (not (atom (car l)))
(del x (car l))
(car l))
l0)))))
(defun _delete(a l)
(format t "~a~%" (del a l)))
(_delete 'nest '(nest (second nest level) (third (nest) level)))
This returns
((SECOND LEVEL (THIRD NIL LEVEL))
And I need
((SECOND LEVEL (THIRD () LEVEL))
I've tried using the ~:S format but that apparently doesn't work with composite structures. I've also tried the substitute function to replace NIL, also with no results.
Two possible solutions:
I. You can use the format directives ~:A or ~:S
(format t "~:a" '()) => ()
However, this directive works only on the top level elements of a list, i.e.
(format t "~:a" '(a b () c))
will not print (A B () C)
but (A B NIL C)
So you need to loop through the list applying the ~:A to each element recursively if it is a cons.
(defun print-parentheses (l)
(cond ((consp l) (format t "(")
(do ((x l (cdr x)))
((null x) (format t ")" ))
(print-parentheses (car x))
(when (cdr x) (format t " "))))
(t (format t "~:a" l)) ))
(print-parentheses '(a b (c () d))) => (A B (C () D))
II. Create a print-dispatch function for empty lists and add it to the pretty print dispatch table:
(defun print-null (stream obj)
(format stream "()") )
(set-pprint-dispatch 'null #'print-null)
(print '(a () b)) => (A () B)
The latter is simpler, but it affects all the environment, which might not be what you want.
We can write an :around method for print-object, for the case when the object to be printed is NIL.
(defvar *PRINT-NIL-AS-PARENS* nil
"When T, NIL will print as ().")
(defmethod print-object :around ((object (eql nil)) stream)
(if *print-nil-as-parens*
(write-string "()" stream)
(call-next-method)))
(defun write-with-nil-as-parens (list)
(let ((*print-nil-as-parens* t))
(write list)))
Example:
CL-USER 73 > (write-with-nil-as-parens '(a b c nil (()) (nil)))
(A B C () (()) (())) ; <- printed
(A B C NIL (NIL) (NIL)) ; <- return value
I've also tried the substitute function to replace NIL, also with no results.
None of the standard substitution functions will work. substitute is a sequence processing function: it will not recurse into the tree structure.
The sublis and subst functions will process the tree structure, but they treat the car and cdr fields of conses equally: if we replace nil throughout a tree structure with :whatever, that applies to all of the terminating atoms, so that (a nil b) becomes (a :whatever b . :whatever).
We must make our out function which is like subst, but only affects car-s:
(defun subcar (old new nested-list)
(cond
((eq nested-list old) new)
((atom nested-list) nested-list)
(t (mapcar (lambda (atom-or-sublist)
(subcar old new atom-or-sublist))
nested-list))))
With this, we can replace nil-s with the character string "()":
[1]> (subcar nil "()" '(a b c nil (e nil f (g nil)) nil))
(A B C "()" (E "()" F (G "()")) "()")
If we pretty-print that, the character strings just print as the data rather than as machine-readable string literals:
[2]> (format t "~a~%" *) ;; * in the REPL refers to result of previous evaluation
(A B C () (E () F (G ())) ())
I hope you understand that nil and () mean exactly the same thing; they are the same object:
[3]> (eq nil ())
T
The only way the symbol token nil can denote an object other than () is if we we are in a package which hasn't imported the nil symbol from the common-lisp package (and nil is interned as a local symbol in that package, completely unrelated to cl:nil):
[1]> (defpackage "FOO" (:use))
#<PACKAGE FOO>
[2]> (in-package "FOO")
#<PACKAGE FOO>
Sanity test: from within package foo check that cl:nil is the same as the () object. We have to refer to the eq function as cl:eq because package foo doesn't import anything from cl:
FOO[3]> (cl:eq cl:nil ())
COMMON-LISP:T
Now let's see if nil in this package is ():
FOO[4]> (cl:eq nil ())
*** - SYSTEM::READ-EVAL-PRINT: variable NIL has no value
OOPS! This is not the standard nil anymore; it doesn't have special the behavior that it evaluates to itself. We must quote it:
FOO[6]> (cl:eq 'nil ())
COMMON-LISP:NIL
Nope, not the () object. Note how the return values of the cl:eq function are printed as COMMON-LISP:NIL or COMMON-LISP:T. Symbols are printed without a package prefix only if they are present in the current package.
say I have two lists in lisp
(setq a '(p q))
(setq b '(1 2))
(car a) is p
(car b) is 1
now I want to define a symbol '(test p 1) but if I use below
(setq c '(test (car a) (car b)))
I get '(test (car a) (car b))
it is understandable, but I just want to know how can I substitute those (car a) to p and (car b) to 1 and form a new symbol of '(test p 1)
Thanks
First off, setq should not be used on unbound variables. You can use setq on established variables. Also for global variables you should use *earmuffs*.
(defparameter *a* '(p q))
(defparameter *b* '(1 2))
(car *a*) ; ==> p
(car *b*) ; ==> 1
The quote will use the quotes structure as data. That means everything expr where you write 'expr will never be evaluated beyond taking the data verbatim. New lists are created with cons. eg.
;; creates/updates binding *x* to point at the newly created list (test p 1)
(defparameter *c* (cons 'test
(cons (car *a*)
(cons (car *b*)
'()))))
cons is the primitive, but CL has several other ways to create lists. eg. the same with the function list:
;; creates/updates binding *x* to point at the newly created list (test p 1)
(defparameter *c* (list 'test (car *a*) (car *b*)))
The second the structure becomes more complex using quasiquote/unquote/unquote-splice is a lot easier.
;; creates/updates binding *x* to point at the newly created list (test p 1)
(defparameter *c* `(test ,(car *a*) ,(car *b*)))
;; more complex example
(defmacro my-let ((&rest bindings) &body body)
`((lambda ,(mapcar #'car bindings)
,#body)
,(mapcar #'cadr bindings)))
(macroexpand-1 '(my-let ((a 10) (b 20)) (print "hello") (+ (* a a) (* b b))))
; ==> ((lambda (a b)
; (print "hello")
; (+ (* a a) (* b b)))
; (10 20))
Note that this is just sugar for the identical structure made with cons, list, and append. It might be optimized for minimal memory use so will share structure. eg. `(,x b c) in a procedure will do (cons x '(b c)) which means if you create two versions their cdr will be eq and you should refrain from mutating these parts.
If you want to make a list the function you want is list:
(list 'test (car a) (car b))`
Will be the list (test p 1).
Note that the purpose of quote (abbreviated ', so '(x) is identical to (quote (x))) is simply to tell the evaluator that what follows is literal data, not code. So, in (list 'test ...), which is the same as (list (quote test) ...) then quote tells the evaluator that test is being used as a literal datum, rather than as the name of a binding, and similarly '(p q) means 'this is a literal list with elements p and q', while (p q) means 'this is a form for evaluation, whose meaning depends on what p is')
To complete the answer from tfb, you can write
`(test ,(car a) ,(car b)
This is strictly the same of
(list 'test (car a) (car b)
In some dialects of LISP, there is a distinction between SET and SETQ, the first one evaluates its first argument so that you need to use the (SET (QUOTE …) …) syntax.
Since in Racket, quoting is not needed in definitions, define behaves as SETQ.
Is there a Racket function that behaves like SET? If no, how to write one?
I tried (define (SET a b) (define (eval a) b) b) but it does not seem to work when providing it to an other language with (provide SET).
Here's my quick attempt at this problem:
;; lib.rkt
#lang racket/base
(provide (rename-out [#set set]
[##%top #%top]
[#set! set!]
[#define define]))
(require syntax/parse/define)
(define env (make-hash))
(define (set x v stx)
(unless (hash-has-key? env x)
(raise-syntax-error #f "undefined id" stx))
(hash-set! env x v))
(define-simple-macro (##%top . x)
(hash-ref
env
'x
(λ () (raise-syntax-error #f "unbound id" (quote-syntax x)))))
(define (#set x v)
(set x v x))
(define-simple-macro (#set! x:id v)
(set 'x v (quote-syntax x)))
(define-simple-macro (#define x:id v)
(begin
(when (hash-has-key? env 'x)
(raise-syntax-error #f "id already defined" (quote-syntax x)))
(hash-set! env 'x v)))
#lang racket/base
(require "lib.rkt")
(define x 1)
(set (if #t 'x 'y) 2)
(add1 x) ; 3
(set! x 3)
(add1 x) ; 4
(add1 y) ; y: unbound id in: y
Note that this differs from original Racket in several ways. For example:
unbound ids are now reported at runtime instead of compile-time.
set! now won't work with set!-transformer.
define can't be used to define functions
define can't be used to shadow an identifier.
For (2) and (3), it's possible to get the original behavior back, but I don't want the answer to be too long, so I didn't include the full functionality. For now, I don't know how to solve (4).
Also note that you can only set identifiers defined via define. If you want to set identifiers defined via lambda, let, etc., you need to redefine these constructs too.
I would do it much less verbose and much simpler.
Since all arguments are evaluated, the set or let's say define% can be defined as a function!
(define (define% x y)
(eval `(define ,x ,y)))
One can even define functions using define% when using old-style form using lambda.
(define 'ab (lambda (x y) (+ x y)))
(ab 3 5) ;; 7
It even behaves correctly in terms of scope
(define (foo x)
(define% 'bar (lambda (x) (+ 1 x)))
(bar (bar (bar x))))
foo
;; #<procedure:foo>
bar
; bar: undefined;
; cannot reference undefined identifier
; [,bt for context]
(foo 3)
6
;; after first call however, bar is available in global environment
;; as pointed out by #AlexKnauf
bar
;; #<procedure:bar>
Thus there are some scoping issues ...
(let ((x 0))
(define% 'counter (lambda () (set! x (+ x 1)) x)))
counter
;; #<procedure>
(counter)
;; 1
(counter)
;; 2
(counter)
;; 3
I'm trying to create a simple memo defun. How can I prevent evaluating of args form in this code?
(defmacro defun/memo (name args &rest body)
`(let ((memo (make-hash-table :test 'equalp)))
(defun ,name ,args
(if (gethash (loop for x in ,args collect x) memo)
(gethash (loop for x in ,args collect x) memo)
(let ((result (progn ,#body)))
(setf (gethash (loop for x in ,args collect x) memo) result)
result)))))
Error:
; in: DEFUN ADD
; (X Y)
;
; caught STYLE-WARNING:
; undefined function: X
;
; compilation unit finished
; Undefined function:
; X
(defmacro defun/memo (name args &rest body)
You generally declare body with &body body, not &rest body.
Variable capture
`(let ((memo (make-hash-table :test 'equalp)))
The memo symbol is going to end in the generated code. If body contains references to memo, for example a symbol that was lexically bound outside of a call to defun/memo, then it will use your variable. You should use a fresh symbol instead, generated inside the macro with gensym (outside of backquotes). For example, you could do the following to avoid evaluating expr twice:
(let ((var-expr (gensym)))
`(let ((,var-expr ,expr))
(+ ,var-expr ,var-expr)))
Loop
(if (gethash (loop for x in ,args collect x) memo)
(gethash (loop for x in ,args collect x) memo)
(let ((result (progn ,#body)))
(setf (gethash (loop for x in ,args collect x) memo) result)
result)))))
What is the following supposed to do?
(loop for x in ,args collect x)
Let's say you define a function with (defun/memo test (a b c) ...), you will inject the literal list of arguments in the above, which will result in code that contains:
(loop for x in (a b c) collect x)
As you saw, the code is now trying to call function a with arguments b and c.
What if you quoted args, in your macro?
(loop for x in ',args collect x)
Then, you would obtain:
(loop for x in '(a b c) collect x)
And now, you are just copying a literal list. When the above generated code is run, it will only build a fresh list (a b c). Is that what you need?
What you want is to take all the arguments of your function, i.e. the list of values you were given. The loop could be replaced by:
(list ,#args)
Which would expand as:
(list a b c)
And here you have all your values, in a list.
But Common Lisp already provides a way to get all arguments as a list:
(defun foo (&rest args)
;; args is bound to a list of values
)
Your generated function could do the same.
Gethash
Also, (if (gethash ...) (gethash ...) other) can be written (or (gethash ...) other). This has the benefits of evaluating the call to gethash only once.
More importantly (thanks #Sylwester), since you are writing a generic macro, you cannot know in advance if nil will be a possible returned value. Having a nil value would make the result recomputed each time, given how the if/or is written. You need to use the secondary return value from gethash to check if the element existed:
(multiple-value-bind (value exists-p) (gethash ...)
(if exists-p
value
(setf (gethash ...) ...)))
Also, if your cached function return multiple values, you may want to grab them all with multiple-value-list and returns them with values-list.
Setf
By the way, the following code:
(let ((result expr))
(setf place result)
result)
... has little reason not to be written as:
(setf place expr)
The return value of setf is required to be the new value. In some cases it could lead to bad style, but here that would be fine.
I'm trying to find the maximum number within a list, then do something with it:
(defun maxList (l)
(if (= (length l) 1)
(first l)
(if (> (first l) (maxList (rest l)))
(first l)
(maxList (rest l))
);if
);if
);defun
(defun try-let (l)
(let (a (maxList l))
(print a)
);let
);defun
However it prints null, yet maxList works. What am I doing wrong ?
You're missing a pair of parentheses:
(let ((a (maxList l)))
This is because let takes a list of bindings as in
(let ((a 1) (b 2) (c 'foo))
expr)
so in this case you have to pass a one-element list containing the binding (a (maxList l))
(defun maxList (l)
(if (= (length l) 1)
Calling LENGTH is not a good idea. It traverses the whole list.
(first l)
(if (> (first l) (maxList (rest l)))
(first l)
(maxList (rest l)))))
Above calls MAXLIST twice. Maybe here a LET is useful? How about the function MAX?
If you compile your function, a Common Lisp system will complain.
CL-USER 35 > (defun try-let (l)
(let (a (maxList l))
(print a)))
TRY-LET
CL-USER 36 > (compile 'try-let)
;;;*** Warning in TRY-LET: MAXLIST is bound but not referenced
This shows that the Lisp compiler thinks MAXLIST is a variable. Something is wrong. Next look up the syntax of LET.
See Special Operator LET, LET*
let ({var | (var [init-form])}*) declaration* form* => result*
Which says that it is a list of variables or a list of (variable initform). So you can see that you have missed to make it a list. You have just written one binding.