There is no equivalent to set-car!, because conses are not mutable. Only vars, refs, atoms, and agents are mutable, and they are simply containers for immutable values. You could put a cons inside an atom and put a new transformed list into the atom. (Note even among schemes set-car! is highly discouraged, and I don't think Racket even has it in core anymore: http://blog.racket-lang.org/2007/11/getting-rid-of-set-car-and-set-cdr.html)
The idiomatic Clojure way of handling this is to always have an immutable environment and contain it in a single environment atom. When you change the environment, you return a new copy of it with your change and put it in to the global env atom. The SICP mutates the environment instead. There's probably a reason for this (late/dynamic binding?) which would have a completely different approach in Clojure. Some more notes: (empty? nil) ;=> true def and defn create namespace-global vars as a side effect--the vars are not lexically scoped! This is NOT like scheme's "define." I suspect all of your inner uses of def and defn should be let and letfn instead. def and defn are used at the top level or (rarely) are used a level or two down to close over some private data (e.g. a def inside a let). However, defs are practically never inside other defs. On Thursday, August 6, 2015 at 12:36:20 PM UTC-5, 杨旸 wrote: > > Hi everyone, > I am current trying to implement a scheme interpreter in clojure following > the instruction on SICP chap4. > > Where I encounter a problem with adding/modifying a def var/fn in > enviroment. > > according to chap4 4.1.3 the set-variable-value! function looks like the > following in scheme: > (define (set-variable-value! var val env) > (define (env-loop env) > (define (scan vars vals) > (cond ((null? vars) > (env-loop (enclosing-environment env))) > ((eq? var (car vars)) > (set-car! vals val)) > (else (scan (cdr vars) (cdr vals))))) > (if (eq? env the-empty-environment) > (error "Unbound variable -- SET!" var) > (let ((frame (first-frame env))) > (scan (frame-variables frame) > (frame-values frame))))) > (env-loop env)) > > > > > But I found there's no set-car! in clojure, which make me have to > re-create the env while loop though the defied variables like: > *https://github.com/zacyang/sicp-in-clj/blob/master/src/sicp/ch4/core.clj > <https://github.com/zacyang/sicp-in-clj/blob/master/src/sicp/ch4/core.clj> > line #348* > > > (defn set-variable-value! > [var-looking-for val-to-be-set env] > > > (defn find-and-change [vars vals] > (cond > (empty? vars) '() > (= (first vars) var-looking-for) (conj (find-and-change (rest vars) > (rest vals)) val-to-be-set) > :else (conj (find-and-change (rest vars) (rest vals)) (first vals)))) > > > (defn env-loop > [e] > > (if (= @env @the-empty-environment) > :ERROR-TRY-SET-UNBOUND-VARIABLE > (let [frame (first-frame e) > frame-vars (frame-variables frame) > frame-vals (frame-values frame)] > > (if (not= @(enclosing-enviroment e) @the-empty-environment) > (extend-enviroment frame-vars frame-vals (env-loop > (enclosing-enviroment e))) > (extend-enviroment > frame-vars > (find-and-change frame-vars frame-vals) > the-empty-environment))))) > > > (env-loop env) > ) > > My question is, is there any good substitution for set-car! in scenarios > where I need just *change* the car and cdr of something created by cons?? > > PS: tried swap! atom , but it will also need to change the whole > environment structure. > > > > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.