8

when I call the math() function, to "times", the REPL returns nil. when I use "add", it works fine... help!

(defn math [opr x y ]
    (if(= opr "times")
        (* x y)
    )
    (if(= opr "add")
        (+ x y)
    )
)
(math "times" 8 8)
2
  • 1
    Remember, the last expression of a function is the expression that is returned. In your code, if opr does not equal "add", the return value is always nil. You may want to consider using a case statement. Commented Feb 10, 2014 at 15:38
  • Minor comment: (if x y) is an expression in clojure and not a statement. I figured I'd mention it to avoid possible further confusion: stackoverflow.com/questions/19132/expression-versus-statement Cheers Commented Feb 11, 2014 at 12:41

4 Answers 4

18

The problem is that your function is a sequence of two-clause if-forms.

  • Clojure performs the elements of the sequence in turn, returning the result of the last.
  • If the condition fails, a two-clause if-form returns nil.

The quickest repair is, as WeGi suggested, to nest the ifs:

(defn math [opr x y]
  (if (= opr "times")
    (* x y)
    (if (= opr "add")
      (+ x y))))

However, there are better ways:

(defn math [opr x y]
  (case opr
    "add" (+ x y)
    "times" (* x y)))

... and, leaving C / Java idioms behind, ...

(defn math [opr x y]
  ((case opr
     "add" +
     "times" *)
   x y))

... or ...

(defn math [opr x y]
  (({"add" +, "times" *} opr) x y))
Sign up to request clarification or add additional context in comments.

Comments

14

I like using a cond statement for multiple conditions.

;; Will return nil if the cond statement fails all the predicates
(defn math [opr x y ]
  (cond (= opr "times") (* x y)
        (= opr "add") (+ x y)))

WeGi is correct in that Clojure will always return the last statement in the function.

Comments

5

condp works when all your predicates have the same structure:

(defn my-calc
  [operator x y]
    (condp = operator
      "times" (* x y)
      "plus" (+ x y))) 

=> (var user/my-calc)
(my-calc "times" 2 3)
=> 6
(my-calc "plus" 2 3)
=> 5

Comments

2

In Clojure the last statement is the Return Statement. So Clojure Checks for "times", even if it is true it checks then for "add" and because your call is made with "times" the second if evaluates to nil. Which is returned.

You could use do or nest your if statements to solve your Problem.

1 Comment

do alone won't solve the problem, as do still returns its tail value. Using do would require a side-effect, and be nasty. cond or if nesting are the only really correct answers here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.