Gabriel Mesquita
Gabriel Mesquita

Reputation: 2411

Implement range function in clojure return error

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)

Upvotes: 1

Views: 141

Answers (3)

Gabriel Mesquita
Gabriel Mesquita

Reputation: 2411

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)))

Upvotes: 1

leetwinski
leetwinski

Reputation: 17859

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)

Upvotes: 1

Carcigenicate
Carcigenicate

Reputation: 45760

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.

Upvotes: 2

Related Questions