I am trying to convert SICP's meta-circular evaluator to Clojure. In setup-environment a call to extend-environment does not compile because I get the error "Attempting to call unbound fn". Here's part of the code:
(... loads of methods for creating and managing environment list)
(def primitive-procedures
(list (list 'car first)
(list 'cdr rest)
(list 'cons conj) ;; TODO: reverse
(list 'null? nil?)
(list 'list list)
(list '+ +)
(list '- -)
(list '* *)
(list '/ /)
;; more primitives
))
(def primitive-procedure-names
#(map [first
primitive-procedures]))
(def primitive-procedure-objects
(fn [] (map (fn [p] (list 'primitive (second p)))
primitive-procedures)))
(def the-empty-environment '())
(defn extend-environment [vars vals base-env]
(if (= (count vars) (count vals))
(conj base-env (make-frame vars vals))
(if (< (count vars) (count vals))
(throw (Throwable. "Too many arguments supplied") vars vals)
(throw (Throwable. "Too few arguments supplied") vars vals))))
;; Added # in front here so it could be called (???)
(defn setup-environment []
#(let [initial-env
(extend-environment (primitive-procedure-names)
(primitive-procedure-objects)
the-empty-environment)] ;; <= that does not work
(define-variable! 'true true initial-env)
(define-variable! 'false false initial-env)
initial-env)))
;; Method for interacting with the evaluator:
(defn driver-loop []
(prompt-for-input input-prompt)
(let [input (read)]
(let [output (m-eval input the-global-environment)]
(announce-output output-prompt)
(user-print output)))
(driver-loop))
(...)
(def the-global-environment (setup-environment))
(driver-loop)
And when I evaluate the extend-environment method I get the following error:
Caused by java.lang.IllegalStateException
Attempting to call unbound fn:
#'scheme-evaluator/extend-environment
Var.java: 43 clojure.lang.Var$Unbound/throwArity
AFn.java: 40 clojure.lang.AFn/invoke
scheme-evaluator.clj: 277 scheme-evaluator/eval7808
I think I am not providing the right type of parameters or I have not created the right type of function. I tried various variations of anonymous methods and passing in parentheses or without, but I don't get it to compile.
Does anyone know what the reason is for this error and how can I fix it?
The definition of
(def primitive-procedure-names
#(map [first
primitive-procedures]))
likely does not do what you intend. As written this defines a function that takes no arguments and returns transducer (which is a function) that will, if applied to a sequence substitute the values 0 and 1 for the functions first and primitive-procedures respectively. I'll demonstrate first with functions and then with values of numbers to make what's happening more clear (hopefully):
user> (into [] (map [first 'example]) [0 1])
[#function[clojure.core/first--4339] example]
user> (into [] (map [1 2]) [0 1])
[1 2]
perhaps you wanted
(def primitive-procedure-names
(map first primitive-procedures))
And may I suggest using the defn form for defining functions and the def form for defining values unless you have a really strong reason not to.
setup-environment is a function that returns a function which will if you call that function return a function that return's the initial-environment unmodified by the calls to define-variable. In Clojure the collection types are immutable so if you want to make several changes to a collection it's necessary to chain the result of adding the first one into the imput of adding the second one, then return the result of adding the second one:
(add-second (add-first initial-value))
which can also be written like this:
(-> initial-value
add-first
add-second)
which is just a shorthand for the example above.
Related
I have the following code:
(ns macroo)
(def primitives #{::byte ::short ::int})
(defn primitive? [type]
(contains? primitives type))
(def pp clojure.pprint/pprint)
(defn foo [buffer data schema]
(println schema))
(defmacro write-fn [buffer schema schemas]
(let [data (gensym)]
`(fn [~data]
~(cond
(primitive? schema) `(foo ~buffer ~data ~schema)
(vector? schema) (if (= ::some (first schema))
`(do (foo ~buffer (count ~data) ::short)
(map #((write-fn ~buffer ~(second schema) ~schemas) %)
~data))
`(do ~#(for [[i s] (map-indexed vector schema)]
((write-fn buffer s schemas) `(get ~data ~i)))))
:else [schema `(primitive? ~schema) (primitive? schema)])))) ; for debugging
(pp (clojure.walk/macroexpand-all '(write-fn 0 [::int ::int] 0)))
The problem is, upon evaluating the last expression, I get
=>
(fn*
([G__6506]
(do
[:macroo/int :macroo/int true false]
[:macroo/int :macroo/int true false])))
I'll explain the code if necessary, but for now i'll just state the problem (it might be just a newbie error I'm making):
`(primitive? ~schema)
and
(primitive? schema)
in the :else branch return true and false respectively, and since i'm using the second version in the cond expression, it fails where it shouldn't (I'd prefer the second version as it would be evaluated at compile time if i'm not mistaken).
I suspect it might have something to do with symbols being namespace qualified?
After some investigations (see edits), here is a working Clojure alternative. Basically, you rarely need recursive macros. If you
need to build forms recursively, delegate to auxiliary functions and call them from the macro (also, write-fn is not a good name).
(defmacro write-fn [buffer schemas fun]
;; we will evaluate "buffer" and "fun" only once
;; and we need gensym for intermediate variables.
(let [fsym (gensym)
bsym (gensym)]
;; define two mutually recursive function
;; to parse and build a map consisting of two keys
;;
;; - args is the argument list of the generated function
;; - body is a list of generated forms
;;
(letfn [(transformer [schema]
(cond
(primitive? schema)
(let [g (gensym)]
{:args g
:body `(~fsym ~schema ~bsym ~g)})
(sequential? schema)
(if (and(= (count schema) 2)
(= (first schema) ::some)
(primitive? (second schema)))
(let [g (gensym)]
{:args ['& g]
:body
`(doseq [i# ~g]
(~fsym ~(second schema) ~bsym i#))})
(reduce reducer {:args [] :body []} schema))
:else (throw (Exception. "Bad input"))))
(reducer [{:keys [args body]} schema]
(let [{arg :args code :body} (transformer schema)]
{:args (conj args arg)
:body (conj body code)}))]
(let [{:keys [args body]} (transformer schemas)]
`(let [~fsym ~fun
~bsym ~buffer]
(fn [~args] ~#body))))))
The macro takes a buffer (whatever it is), a schema as defined by your language and a function to be called for each value being visited by the generated function.
Example
(pp (macroexpand
'(write-fn 0
[::int [::some ::short] [::int ::short ::int]]
(fn [& more] (apply println more)))))
... produces the following:
(let*
[G__1178 (fn [& more] (apply println more)) G__1179 0]
(clojure.core/fn
[[G__1180 [& G__1181] [G__1182 G__1183 G__1184]]]
(G__1178 :macroo/int G__1179 G__1180)
(clojure.core/doseq
[i__1110__auto__ G__1181]
(G__1178 :macroo/short G__1179 i__1110__auto__))
[(G__1178 :macroo/int G__1179 G__1182)
(G__1178 :macroo/short G__1179 G__1183)
(G__1178 :macroo/int G__1179 G__1184)]))
First, evaluate buffer and fun and bind them to local variables
Return a closure which accept one argument and destructures it according to the given schema, thanks to Clojure's destructuring capabilities.
For each value, call fun with the appropriate arguments.
When the schema is [::some x], accept zero or more values as a vector and call the function fun for each of those values. This needs to be done with a loop, since the size is only know when calling the function.
If we pass the vector [32 [1 3 4 5 6 7] [2 55 1]] to the function generated by the above macroexpansion, the following is printed:
:macroo/int 0 32
:macroo/short 0 1
:macroo/short 0 3
:macroo/short 0 4
:macroo/short 0 5
:macroo/short 0 6
:macroo/short 0 7
:macroo/int 0 2
:macroo/short 0 55
:macroo/int 0 1
In this line:
`(do ~#(for [[i s] (map-indexed vector schema)]
((write-fn buffer s schemas) `(get ~data ~i)))))
you are calling write-fn, the macro, in your current scope, where s is just a symbol, not one of the entries in schema. Instead, you want to emit code that will run in the caller's scope:
`(do ~#(for [[i s] (map-indexed vector schema)]
`((write-fn ~buffer ~s ~schemas) (get ~data ~i)))))
And make a similar change to the other branch of the if, as well.
As an aside, it looks to me at first glance like this doesn't really need to be a macro, but could be a higher-order function instead: take in a schema or whatever, and return a function of data. My guess is you're doing it as a macro for performance, in which case I would counsel you to try it out the slow, easy way first; once you have that working you can make it a macro if necessary. Or, maybe I'm wrong and there's something in here that fundamentally has to be a macro.
I want to get the indices of nil elements in a vector eg.
[1 nil 3 nil nil 4 3 nil] => [1 3 4 7]
(defn nil-indices [vec]
(vec (remove nil? (map
#(if (= (second %) nil) (first %))
(partition-all 2 (interleave (range (count vec)) vec)))))
)
Running this code results in
java.lang.IllegalArgumentException: Key must be integer
(NO_SOURCE_FILE:0)
If I leave out the (vec) call surrounding everything, it seems to work, but returns a sequence instead of a vector.
Thank you!
Try this instead:
(defn nil-indices [v]
(vec (remove nil? (map
#(if (= (second %) nil) (first %))
(partition-all 2 (interleave (range (count v)) v))))))
Clojure is a LISP-1: It has a single namespace for both functions and data, so when you called (vec ...), you were trying to pass your result sequence to your data as a parameter, not to the standard-library vec function.
See other answer for your problem (you are shadowing vec), but consider using a simpler approach.
map can take multiple arguments, in which case they are passed as additional arguments to the map function, e.g. (map f c1 c2 ...) calls (f (first c1) (first c2) ...) etc, until one of the sequence arguments is exhausted.
This means your (partition-all 2 (interleave ...)) is a very verbose way of saying (map list (range) v). There is also a function map-indexed which does the same thing. However, it only takes one sequence argument, so (map-indexed f c1 c2) is not legal.
Here is your function rewritten for clarity using map-indexed, threading, and nil?:
(defn nil-indices [v]
; Note: map fn called like (f range-item v-item)
; Not like (f (range-item v-item)) as in your code.
(->> (map-indexed #(when (nil? %2) %1) v) ;; like (map #(when ...) (range) v)
(remove nil?)
vec))
However, you can do this instead with reduction and the reduce-kv function. This function is like reduce, except the reduction function receives three arguments instead of two: the accumulator, the key of the item in the collection (index for vectors, key for maps), and the item itself. Using reduce-kv you can rewrite this function even more clearly (and it will probably run faster, especially with transients):
(defn nil-indices [v]
(reduce-kv #(if (nil? %3) (conj %1 %2) %1) [] v))
i need to write code like this in clojure.
-- haskell
fns = map (,) [1..3]
head fns $ 1
-- => (1,1)
fns <*> [1..3]
-- => [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
doesn't work
(def fns (map (partial list) (range 1 3)))
((first fns) 1)
;; => ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
works, but i think this isn't idiomatic way
(def fns (map (fn [x] `(partial list ~x)) (range 1 3)))
((eval (first fns)) 1)
;; => (1 1)
The function (partial list) is equivalent to just the function list. It's not like haskell where everything is curried - I think you intended partial to see that it's been given only one argument, list, and curry itself up to wait for a second argument. But really that should be (partial partial list): you are attempting to partially apply the function partial itself.
Note also that partially-applied functions are not as common in clojure as they are in haskell, partly because they just don't read so well. Instead of (map (partial partial list) (range 1 3)), if I wanted to build a list of functions like this, I would probably write (for [i (range 1 3)] (fn [j] (list i j))).
I need to define a function called
(get-all-pairs key seq)
It returns the list of all pairs in seq that have key as their first element. If no pairs match, then the empty list is returned.
For example,if I def pets
(def pets
'((cat 1) (dog 1) (fish 1) (cat 2) (fish 2))
)
(get-all-pairs 'cat pets) returns ((cat 1) (cat 2)), and (get-all-pairs 'bird pets) returns '().
Here is my try:
(defn get-all-pairs [key seq]
(cond
(= key (first(first(seq)))) (cons (first seq)
(get-all-pairs key (rest seq)))
:else '()))
But it doesnot work. If I call it, it messages as follow:
#'proj2.proj2/pets
=> (get-all-pairs 'cat pets)
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn proj2.proj2/get-all-pairs (proj2.clj:20)
I don't know where the problem is. How to fix it?
The immediate error is because you have too many parens in your definition: (first (first (seq))) should just be (first (first seq)). Once you fix that, your function should run to completion, but give you the wrong answer: think about whether () is really what you want in your else case.
Once you've worked out your by-hand recursive approach, try to figure out what is going on in this solution:
(defn get-all-pairs [k pairs]
(filter #(= k (first %)) pairs))
You are on the right track, but sort of over-thinking this one. For allows you to abstract away many of the things you are attempting to do manually. In this case, we can generate a seq and iteratively use an if expression with :when.
(defn get-all-pairs [animal L]
(for [k L
:when (= animal (first k))]
k))
I'm converting some Scheme code to Clojure. The original uses a dispatching pattern that's very similar to multimethods, but with an inverted approach to the matching predicates. For example, there a generic function "assign-operations". The precise implementation details aren't too important at the moment, but notice that it can take a list of argument-predicates.
(define (assign-operation operator handler . argument-predicates)
(let ((record
(let ((record (get-operator-record operator))
(arity (length argument-predicates)))
(if record
(begin
(if (not (fix:= arity (operator-record-arity record)))
(error "Incorrect operator arity:" operator))
record)
(let ((record (make-operator-record arity)))
(hash-table/put! *generic-operator-table* operator record)
record)))))
(set-operator-record-tree! record
(bind-in-tree argument-predicates
handler
(operator-record-tree record)))))
The dispatched functions supply these predicates, one per argument in the arity of the function.
(assign-operation 'merge
(lambda (content increment) content)
any? nothing?)
(assign-operation 'merge
(lambda (content increment) increment)
nothing? any?)
(assign-operation 'merge
(lambda (content increment)
(let ((new-range (intersect-intervals content increment)))
(cond ((interval-equal? new-range content) content)
((interval-equal? new-range increment) increment)
((empty-interval? new-range) the-contradiction)
(else new-range))))
interval? interval?)
Later, when the generic function "merge" is called, each handler is asked if it works on the operands.
As I understand multimethods, the dispatch function is defined across the set of implementations, with dispatch to a specific method based on the return value of the dispatch-fn. In the Scheme above, new assign-operation functions can define predicates arbitrarily.
What would be an equivalent, idiomatic construct in Clojure?
EDIT: The code above comes from "The Art of the Propagator", by Alexey Radul and Gerald Sussman.
You can do this with Clojure's multimethods fairly easily - the trick is to create a dispatch function that distinguishes between the different sets of predicates.
The easiest way to do this is probably just to maintain a vector of "composite predicates" that apply all of the individual predicates to the full argument list, and use the index of this vector as the dispatch value:
(def pred-list (ref []))
(defn dispatch-function [& args]
(loop [i 0]
(cond
(>= i (count #pred-list)) (throw (Error. "No matching function!"))
(apply (#pred-list i) args) i
:else (recur (inc i)))))
(defmulti handler dispatch-function)
(defn assign-operation [function & preds]
(dosync
(let [i (count #pred-list)]
(alter pred-list conj
(fn [& args] (every? identity (map #(%1 %2) preds args))))
(defmethod handler i [& args] (apply function args)))))
Then you can create operations to handle whatever predicates you like as follows:
(assign-operation (fn [x] (/ x 2)) even?)
(assign-operation (fn [x] (+ x 1)) odd?)
(take 15 (iterate handler 77))
=> (77 78 39 40 20 10 5 6 3 4 2 1 2 1 2)