I keep getting a java.lang.IllegalArgumentException: Don't know how to create ISeq from: four_cloj.core$my_fib
(defn my-fib []
(let [a 0 b 1]
(lazy-seq (cons a (my-fib b (+ a b))))))
Anyone got any ideas?
Your current issue is that you are recursively calling my-fib with two arguments.
(my-fib b (+ a b))
But, the function argument list for my-fib contains no arguments
(defn my-fib []
Related
I am trying to implement the range function in clojure, but my implementation is returning an error that I cannot understand. Here it is:
(defn implement-range [a b] (
if (= a b)
(conj nil b)
((conj nil a) (implement-range (inc a) b))))
I am trying to do in a recursive way, it is not complete yet, since I am stuck with this error:
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn user/implement-range
I think that it is a parentheses problem that I cannot see (I am a newbie in clojure :) ). Any ideas?
Thanks in advance for any help
EDIT:
I would like to return something like (1 2 3 4) if I call the function like this:
(implement-range 1 5)
You were close:
(defn implement-range [a b]
(if (>= a b)
'()
(conj (implement-range (inc a) b) a)))
(implement-range 0 5)
=> (0 1 2 3 4)
First, the main problem is that ((conj nil a) (implement-range (inc a) b)))) is attempting to call (conj nil a) as a function, with (implement-range (inc a) b) as the argument. I'm not entirely sure what you're trying to do here, but this definitely isn't what you want.
I made three changes:
You need to conj the current number to the result of the recursive call. This is "unsafe" recursion since the recursive call isn't in tail position, but while messing around, that's not a big deal. You'll want to use an alternate method though if you intend to use this for real.
If you enter a b that is larger than a, it will explode. I fixed this by changing the base case condition.
Your base case didn't make any sense. Once the recursion stops, you'll want to add to an empty list.
Just a side note, any time you see ((, little alarm bells should go off. This is often a sign of a problem, unless you're getting fancy and writing something like ((comp str inc) 1); where the first form in the expression evaluates to a function.
the simplest (and the most classic one) would be something like this:
(defn implement-range [a b]
(when (< a b)
(cons a (implement-range (inc a) b))))
user> (implement-range 1 20)
;;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
I did some research and found that use conj this way does not make any sense. So I came up with this:
(defn implement-range [a b] (
if (= a b)
b
(flatten (list a (implement-range (inc a) b)))))
So if I call the function with the 1 4 parameters the result will be:
(1 2 3 4)
But, since I am trying to implement a function such like the range function, it needs to remove the last element yet.
EDIT 1
The final function that I wrote looked like this:
(defn implement-range [a b] (
if (= a b)
nil
(remove nil? (flatten (list a (implement-range (inc a) b))))))
EDIT 2
After some more research I've figured out another way to solve this, with less lines of code:
(defn new-range [a b]
(take (- b a) (iterate inc a)))
This works:
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (tri* new-sum (+ n 1)))))))
but when I use recur in it, I get a CompilerException:
Mismatched argument count to recur, expected 0 args, got: 2
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (recur new-sum (+ n 1)))))))
lazy-seq is a macro which expands to code involving a zero-arg thunk that can be called later as the sequence is realized. You can see that the recur form is captured as the body of this thunk by doing
(macroexpand '(lazy-seq (recur new-sum (+ n 1))))
to get
(new clojure.lang.LazySeq (fn* [] (recur new-sum (+ n 1))))
which shows that the target of recur is the thunk, not tri*.
Another way to think about all of this is that the original call to tri* has long since completed (and returned a Cons object containing LazySeq rest object) by the time recur would be “evaluated.”
Your first version of tri* is fine in that the recursive call to tri* doesn't grow the stack, but instead simply creates a new set of Cons / LazySeq objects.
I'm new to Clojure and am grasping to understand the concepts. The REPL helpfully lets me get docs of "stuff". So I want to define a function...
clojure-noob.core> (doc fn)
-------------------------
clojure.core/fn
(fn name? [params*] exprs*)
(fn name? ([params*] exprs*) +)
Special Form
...
name => symbol
...and the doc suggests that I can name my function. The REPL accepts my function, but I can't invoke it, "Unable to resolve symbol.."...
clojure-noob.core> (fn add-pair [a b] (+ a b))
#<core$eval3364$add_pair__3365 clojure_noob.core$eval3364$add_pair__3365#6fb5a33b>
clojure-noob.core> (add-pair 1 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: add-pair in this context, compiling:(/private/var/folders/1g/fnytl2x93sx6hp2f1rsf4h1r5xtqv_/T/form-init6828995349142227131.clj:1:1)
clojure-noob.core>
Leaving off the name and building a proper def of the fn does get the job done as does leveraging the defn macro thing...
clojure-noob.core> (def another-add-pair (fn [a b] (+ a b)))
clojure-noob.core> (another-add-pair 1 2)
3
clojure-noob.core> (defn yet-another-add-pair [a b] (+ a b))
#'clojure-noob.core/yet-another-add-pair
clojure-noob.core> (yet-another-add-pair 3 4)
7
There is obviously something I don't understand about the output of (doc fn). In particluar, what is the name? there and what can you do with it? I am as much trying to learn how to read the docs as well as understand the fn special form. Thanks.
calling (fn add-pair [a b] (+ a b)) from the REPL builds an instance of that function and then prints it to the screen. After that it goes away and is not saved anywhere. This is why you can't get it's docs using the doc function. The name parameter in the fn literal is often used for making recursive calls and does not mean that it will be saved by that name anywhere.
if you call (defn add-pair [a b] (+ a b)) then it saves the function into the namespace and then the doc function is able to look it up later and print it's doc string.
A fn form evaluates to a function object.
You can apply the function object immediately:
((fn [a b] (+ a b)) 1 1) ;=> 2
If you want to refer to the function object locally, use a let
binding:
(let [add-pair (fn [a b] (+ a b))] (add-pair 1 1)) ;=> 2
A function object is as much a value as 1
or [3 :a]:
(let [double (fn [n] (* 2 n))]
(({double (comp double double)} double) 3)
;=> 12
The let binding does not exist within the fn form - you need a
name parameter for that:
((fn fact [n] (case n, 0 1, (* n (fact (dec n))))) 5) ;=> 120
letfn does both:
(letfn [(fact [n] (case n, 0 1, (* n (fact (dec n)))))] (fact 5)) ;=> 120
If you want the function to be accessible globally, bind it to a
var using def:
(def fact (fn fact [n] (case n, 0 1, (* n (fact (dec n))))))
(fact 5) ;=> 120
The defn macro does the same more succinctly:
(defn fact [n] (case n, 0 1, (* n (fact (dec n)))))
(fact 5) ;=> 120
going through the exercises in the fp-oo book and i'm having trouble with an early exercise to add squares. Here's my code:
(defn square [n]
(* n n))
(defn add-squares [l]
(cond
(nil? l) 0
:else (+ (square (first (l))) (add-squares (rest (l))))))
This example:
(add-squares '(2 2 2 2))
should return
16
but fails with this exception:
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn user/add-squares (NO_SOURCE_FILE:4)
which i guess means i'm trying to pass a function somewhere instead of a list which was expected. Can someone tell me which part of the code is the culprit?
Thanks,
James
This is wrong:
(first (l))
This means that you are calling l as a function.
You should use:
(first l)
And of course, the same thing for (rest (l))
I basically want this:
(defn mymax
([a b] (if (> a b) a b))
([a b & rest] (apply recur (conj rest (mymax a b)))))
So that: (mymax 1 2 3 4) tail calls (mymax 2 3 4) which tail calls (mymax 3 4)
I see the problem that "apply" stops recur being in the tail position, which means it won't work. But I don't see how I can not use apply for variable arguement functions
[Note, I know you can solve this particular problem with reduce. Just wondering if you can do tail-call-recursion with variable params]
Make the function take a single vector as an argument rather than using aruguments as the sequence of values. That would allow you to get rid of apply.
(defn mymax [[a b & rest]]
(let [m (if (> a b) a b)]
(if (not rest)
m
(recur (conj rest m)))))