henninb
henninb

Reputation: 131

clojure - function let variable not mutable

Hello I am getting a runtime error message while trying to run my clojure program.

Caused by: java.lang.IllegalArgumentException: Cannot assign to non-mutable: x

Please let me know what I am not understanding about the mutable variable so I can solve this code issue. Thanks in advance.

(defn gcd [a b]
  (if (zero? b)
    a
    (recur b (mod a b))
  )
)

(defn euler_phi [n]
  (let [x 0]
    (loop [idx_i 1]
      (when (= 1 (gcd idx_i n))
        (set! x (inc x))
        (print " * ")
      )
      (when (< idx_i n)
        (recur (inc idx_i))
      )
    )
    x
  )
)

Upvotes: 0

Views: 746

Answers (2)

Alan Thompson
Alan Thompson

Reputation: 29958

If you want to write imperative-style code in Clojure, just use an atom any place you would use a Java variable:

(ns tst.demo.core
  (:use demo.core ) )

(defn gcd [a b]
  (if (zero? b)
    a
    (recur b (mod a b))))

(defn euler-phi [n]
  (let [x (atom 0)]
    (loop [idx 1]
      (when (= 1 (gcd idx n))
        (swap! x inc)
        (print " * "))
      (when (< idx n)
        (recur (inc idx))))
    @x))

(dotimes [n 30]
  (print "n:" n "   ")
  (let [result (euler-phi n)]
    (println "    result=" result)))

With results:

n: 0     *     result= 1
n: 1     *     result= 1
n: 2     *     result= 1
n: 3     *  *     result= 2
n: 4     *  *     result= 2
n: 5     *  *  *  *     result= 4
n: 6     *  *     result= 2
n: 7     *  *  *  *  *  *     result= 6
n: 8     *  *  *  *     result= 4
n: 9     *  *  *  *  *  *     result= 6
n: 10     *  *  *  *     result= 4
n: 11     *  *  *  *  *  *  *  *  *  *     result= 10
n: 12     *  *  *  *     result= 4
n: 13     *  *  *  *  *  *  *  *  *  *  *  *     result= 12
n: 14     *  *  *  *  *  *     result= 6
n: 15     *  *  *  *  *  *  *  *     result= 8
n: 16     *  *  *  *  *  *  *  *     result= 8
n: 17     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 16
n: 18     *  *  *  *  *  *     result= 6
n: 19     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 18
n: 20     *  *  *  *  *  *  *  *     result= 8
n: 21     *  *  *  *  *  *  *  *  *  *  *  *     result= 12
n: 22     *  *  *  *  *  *  *  *  *  *     result= 10
n: 23     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 22
n: 24     *  *  *  *  *  *  *  *     result= 8
n: 25     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 20
n: 26     *  *  *  *  *  *  *  *  *  *  *  *     result= 12
n: 27     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 18
n: 28     *  *  *  *  *  *  *  *  *  *  *  *     result= 12
n: 29     *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *     result= 28

Here is a more functional version of your code:

(ns tst.demo.core
  (:use demo.core tupelo.test )
  (:require [tupelo.core :as t] ))
(t/refer-tupelo)

(defn gcd [a b]
  (if (zero? b)
    a
    (recur b (mod a b))))

(defn euler-phi [n]
  (apply +
    (t/forv [idx (t/thru 1 n)]
      (if (= 1 (gcd idx n))
        1
        0))))

(dotimes [n 30]
  (println "n:" n "    result=" (euler-phi n)))

with results:

n: 0     result= 0
n: 1     result= 1
n: 2     result= 1
n: 3     result= 2
n: 4     result= 2
n: 5     result= 4
n: 6     result= 2
n: 7     result= 6
n: 8     result= 4
n: 9     result= 6
n: 10     result= 4
n: 11     result= 10
n: 12     result= 4
n: 13     result= 12
n: 14     result= 6
n: 15     result= 8
n: 16     result= 8
n: 17     result= 16
n: 18     result= 6
n: 19     result= 18
n: 20     result= 8
n: 21     result= 12
n: 22     result= 10
n: 23     result= 22
n: 24     result= 8
n: 25     result= 20
n: 26     result= 12
n: 27     result= 18
n: 28     result= 12
n: 29     result= 28

Note that the result for n=0 is different..... I didn't try to debug it.

Upvotes: 0

Ibrahim Albarghouthi
Ibrahim Albarghouthi

Reputation: 56

set! Doc you cannot assign to function params or local bindings. Only Java fields, Vars, Refs and Agents are mutable in Clojure. See http://clojure.org/special_forms for more information.

Upvotes: 2

Related Questions