I converted the Structure and Interpretation of Computer Programs (SICP) version of the meta-circular evaluator to Clojure. The main difference (besides syntax) is the handling of the environment structure. Since you cannot use set-car! and set-cdr! in Clojure, these are implemented via an atom holding a map (copied from the code of Greg Sexton's chapter 4 notes on GitHub, which I believe has the same problem with not being able to define a procedure).
The code of the two evaluators can be found here:
SICP Evaluator Scheme
Converted Evaluator Clojure
Unfortunately defining a procedure does not work properly. What I expect to happen is this:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
< Environment printed >
;;; M-Eval input:
(add1 10)
;;; M-Eval value:
11
Note: it is basically Scheme code that is entered except for define which is called defn.
Here defining add1 stores a procedure in the environment structure and when it is called with (add1 10) the symbol add1 is looked up in the environment and the procedure created by the evaluator is applied to 10, resulting in 11.
What I see however is this:
;;; M-Eval input:
(defn (add1 x) (+ x 1))
;;; M-Eval value:
{add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (#object[clojure.lang.Atom 0x7c197838 {:status :ready, :val {add1 (procedure (x) (((+ x 1))) (... et cetera)
I get a very long environment output (it looks like the created procedure has an environment that contains the procedure itself) and then a StackOverflowError.
Unhandled clojure.lang.Compiler$CompilerException
Error compiling:
scheme-evaluator.clj:316:1
(...)
Caused by java.lang.StackOverflowError
(No message)
For clarity, I put the eval below. But I think the whole code needs to be run to properly see what is wrong.
(defn eval [exp env]
(cond (self-evaluating? exp) exp
(variable? exp) (lookup-variable-value exp env)
(quoted? exp) (text-of-quotation exp)
(assignment? exp) (eval-assignment exp env)
(definition? exp) (eval-definition exp env)
(if? exp) (eval-if exp env)
(lambda? exp) (make-procedure (lambda-parameters exp)
(lambda-body exp)
env)
(begin? exp) (eval-sequence (begin-actions exp) env)
(cond? exp) (eval (cond->if exp) env)
(application? exp) (apply (eval (operator exp) env)
(list-of-values (operands exp) env))
:else (throw (Throwable. (str "Unknown expression type \"" exp "\" -- EVAL")))))
I hope someone can help me with this and perhaps shine some light on what is going wrong here.
The problem is lambda-body procedure. The lambda list contains 3 elements; tag, parameters and its body. However retrieving the body by lambda-body uses cddr instead of caddr, thus the result get wrapped by extra list. So if you change the definition of lambda-body like this:
(defn lambda-body [exp] (third exp))
then you can get result computed.
NB: if you want to avoid stack overflow error, then you can change eval-definition or define-variable! to return something else such as name of the given exp.
Related
(defn my-loop [x]
(cond (> x 1)
((println x)
(my-loop (- x 1)))
)
)
;; => #'user/my-loop
user> (my-loop 10)
Why do i get a null pointer exception, when executing this function?
Is this not a normal recursion?
You are invoking the return of (println x) with the additional layer of parentheses. println returns nil so invoking it will lead to the NullPointerException.
To evaluate more than one form where only one is expected use the do special form, which evaluates any number of forms and returns the value of the last one:
(defn my-loop [x]
(cond (> x 1) (do
(println x)
(my-loop (- x 1)))))
In this case, when can replace a one armed cond and do
(defn my-loop [x]
(when (> x 1)
(println x)
(my-loop (- x 1))))
The code should typically look something like so:
(defn my-loop
"Some docstring"
[x]
(cond
(> x 1) (println x)
:else (my-loop (- x 1))))
Keeping to good formatting helps to see problems early.
You may also be interested in this list of documentation sources, especially the Clojure CheatSheet & the book "Getting Clojure".
I am generating lists such as the following, with operators, numbers and parameters:
'(* (+ 3 param1) param2)
That I want to evaluate and test with different parameters. But reading around it doesn't look like I can change those values at runtime if I use the eval procedure.
Is there a clean way to do this?
Here's an alternative, using quasiquoting:
(eval `(* (+ 3 ,param1) ,param2))
In the above line, the two parameters will get evaluated at runtime before the call to eval. For example:
(define param1 42)
(define param2 43)
(eval `(* (+ 3 ,param1) ,param2))
=> 1935
Note that
> (eval '(let ([param1 42]
[param2 43])
(* (+ 3 param1) param2)))
1935
So wrap your expression in a let before you evaluate it.
If you want to manage explicitly the binding of values to the variables in the expression, in order to evaluate the expression with different values, you could create and manipulate an explicit “environment”.
; create an empty environment
(define (make-env)
'())
; create a new environment extending env with a new bind (var . value)
(define (bind var value env)
(cons (cons var value) env))
; lookup var in env, if present returns the value, otherwise returns itself
(define (lookup var env)
(cond ((null? env) var)
((eq? (caar env) var) (cdar env))
(else (lookup var (cdr env)))))
(define (myEval exp env)
(define (substitute exp env)
(cond ((null? exp) '())
((number? exp) exp)
((symbol? exp) (lookup exp env))
(else (cons (substitute (car exp) env) (substitute (cdr exp) env)))))
(eval (substitute exp env)))
(myEval '(* (+ 3 param1) param2) (bind 'param1 10 (bind 'param2 20 (make-env))))
The function myEval substitutes all the variables inside the expression with the corresponding value inside the environment, then call the predefined function eval. Note that the definition of an environment is the first step in defining your own eval function.
Say I have the following code:
(defmacro test1 [x]
(list 'fn '[y]
(if (pos? x)
'(println y)
'(println (- y)))))
It does what I need, composes a function based on x, and leaves no references to x. For example, (test1 1) macroexpands into (fn* ([y] (println y))).
Now, I'd like to rewrite it using syntax quoting. This is what I have so far:
(defmacro test2 [x]
`(fn [y#]
(if ~(pos? x)
(println y#)
(println (- y#)))))
This does exactly the same, with one exception: it leaves an (if true ..) expression in the expanded expression:
(fn* ([y__12353__auto__]
(if true
(clojure.core/println y__12353__auto__)
(clojure.core/println (clojure.core/- y__12353__auto__)))))
This might not be an issue if the compiler can optimize it out. Still, is there a way I could omit it?
When you use test2 it will unquote the whole form (pos? x) which will work at compile time if it's a constant number or perhaps a gloabl that is already defined, but not if you pass a lexically scoped variable name that doesn't exist yet.
Thus, you really want this instead:
(defmacro test2 [x]
`(fn [y#]
(if (pos? ~x) ; just unquote x, not the whole predicate expression
(println y#)
(println (- y#)))))
(macroexpand '(test2 y))
; ==>
; (fn* ([y__1__auto__]
; (if (clojure.core/pos? y)
; (clojure.core/println y__1__auto__)
; (clojure.core/println (clojure.core/- y__1__auto__)))))
(defn test-it []
(let [y -9]
(test2 y)))
((test-it) 5) ; prints "-5"
Feel free to try this with your version. (hint: You'll get an Exception since clojure.lang.Symbol cannot be cast to java.lang.Number)
UPDATE
Since you want to make the function based on a constant you need to write it a little differently:
(defmacro test3 [x]
(assert (number? x) "needs to be a compile time number")
(if (pos? x)
`(fn [y#] (println y#))
`(fn [y#] (println (- y#)))))
Now you'll get an error if you use (test3 x) since x is not a number but get what you want when you evaluate (test3 -10) since -10 is a number we can work with compile time. I'm not sure you'll notice a speed improvement though since these are hardly heavy algorithms.
I have written a function that sums the members of a list. Pretty straightforward, newbie stuff, but for some reason it returns nil, and I am at a loss as to why: this should be a no-brainer. The implementation and function call follow.
The implementation:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
The call to the function:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
Meanwhile, I have a debugging version with print statements added, and I have been able to verify that the implementation works as it should.
Debugging version:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
Call to debugging version:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
The development tools I am using are Vim plugged into the Leiningen REPL. Any hints about what I'm doing wrong here would be most appreciated.
You used if in a wrong way. Consider the following code: I intentionally simplified the code to make it clear what happens.
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
What happens if you run (xxx [1])? Perhaps you expect the code will return "one", however, it returns nil. Why?
Function returns value of its last expression, in this case, the last line (if (> (count v) 2) "more"). If you pass [1], the first if expression returns "one", which is ignored. The second if will return nil, which is also ignored. The third and the last will return nil, which is the return value of the function.
Perhaps the simplest way to compute sum of elements is:
(defn add-elements [xs] (apply + xs))
or
(defn add-elements [xs] (reduce + xs))
Your code can be reimplemented in much simpler way:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))
The parentheses are wrong, or at least suboptimal, and you have no base case that returns total. (About the parentheses: Your indentation, which is correct given the parentheses, shows this: Each if is on the same level; none of them are in the "else" position.) Here's one correct version:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
You get nil as the return value because when the last if test fails, it goes to the else clause, which in this case is an empty end of a list, i.e. nil.
However, the multiple ifs can be replaced with one cond. You can also use ffirst for (first (first, fnext instead of (first (rest, and nnext instead of (rest (rest. It would also be more idiomatic to use a predicate such as empty? instead of checking for count equal to 0; I used count for the base case simply to maintain the parallel with your existing code. The simplest version might be:
(defn add-list-members [x] (apply + x))
You could also use reduce for a very simple version. You may just have wanted to experiment with recur, though.
(Well, you could do it without using the embedded else clauses, as in your original, but I wouldn't recomment it, and you still need the empty sequence base case. When you put multiple separate expressions in an function definition, each one of them always gets executed. This is inefficient and, I feel, error prone. Using multiple, separate expressions in a function definition makes sense when you're creating side effects--e.g. adding print statements for debugging.)
I'm having trouble pasting multiple function definitions into the clojure repl running in tmux. (the general case is pasting over a large amount of code)
When I manually paste the following clojure definitions (as one paste operation) into the clojure repl not running in tmux it pastes over fine.
But when pasting from tslime or directly into tmux running the clojure repl, some of the final defs get their text garbled and only some of the definitions get completed properly. (gets screwy around the make-exponentiation def)
Anyone else experience this or have any ideas on what might be going on?
; Some expiriments and exercises for
; Lecture 3B of SICP
(ns deriv)
(defn variable?
[x]
(symbol? x))
(defn same-variable?
[v1 v2]
(and (variable? v1) (variable? v2) (= v1 v2)))
(defn sum?
[x]
(and (seq? x) (= (first x) '+)))
(defn make-sum
[a1 a2]
(cond
(= a1 0) a2
(= a2 0) a1
(and (number? a1) (number? a2)) (+ a1 a2)
:else (list '+ a1 a2)))
(defn make-product
[a1 a2]
(cond
(or (= a1 0) (= a2 0)) 0
(= a1 1) a2
(= a2 1) a1
(and (number? a1) (number? a2)) (* a1 a2)
:else (list '* a1 a2)))
(defn product?
[x]
(and (seq? x) (= (first x) '*)))
(defn addend
[[op addend & augend]]
addend)
(defn augend
[[op addend & augend]]
(if (next augend)
(conj augend '+)
(first augend)))
(defn multiplier
[[op multiplier & multiplicand]]
multiplier)
(defn multiplicand
[[op multiplier & multiplicand]]
(if (next multiplicand)
(conj multiplicand '*)
(first multiplicand)))
(defn exponentiation?
[x]
(and (seq? x) (= (first x) '**)))
(defn base
[[op base exponent]]
base)
(defn exponent
[[op base exponent]]
exponent)
(defn make-exponentiation
[base exponent]
(cond
(= exponent 0) 1
(= exponent 1) base
:else (list '** base exponent)))
(defn deriv
[exp var]
(cond
(number? exp) 0
(variable? exp) (if
(same-variable? exp var)
1
0)
(sum? exp) (make-sum
(deriv (addend exp) var)
(deriv (augend exp) var))
(product? exp) (make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (multiplicand exp)
(deriv (multiplier exp) var)))
(exponentiation? exp) (make-product
(deriv (base exp) var)
(make-product
(exponent exp)
(make-exponentiation
(base exp)
(- (exponent exp) 1))))
:else
(throw (Exception. (str "unknown expression type -- DERIV " exp)))))
I use tmux almost daily. I normally use emacs + swank/slime and don't have issues. JLine seems to avoid this issue as well. I tried rlwrap instead and noticed similar behavior. This most certainly seems to be an rlwrap issue. If you want to keep the same REPL you are using I suggest giving JLine a try. You just need to download the jar and put it in your path or declare it as a Leiningen dependency. You can then start a REPL up with JLine support like so:
java -cp "lib/*:lib/dev/*" jline.ConsoleRunner clojure.main
After that you should be good to go.