関数内に補助関数を作り、その中で親関数の引数を利用した場合の挙動の比較
Project Euler の Problem-5 をClojureに移植していたらハマった・・・
def problem5(m:BigInt):BigInt = { def checkloop(n:BigInt, s:BigInt):BigInt = { if (n % m == BigInt(0)) n else checkloop(n+s, s) } if (m == BigInt(1)) m else { val newm = problem5(m-1); checkloop(newm,newm) } }
(define (problem5 m) (define (checkloop n s) (if (= (modulo n m) 0) n (checkloop (+ n s) s))) (if (= m 1) m (let1 newm (problem5 (- m 1)) (checkloop newm newm))))
(defn problem5 [m] (defn checkloop [n s] (if (= (mod n m) 0) n (checkloop (+ n s) s))) (if (= m 1) m (let [newm (problem5 (- m 1))] (checkloop newm newm))))
実行結果はそれぞれ
scala> problem5(20) res0: BigInt = 232792560 gosh> (problem5 20) 232792560 user=> (problem5 20) 1
挙動の理解はこう・・・
ScalaとGaucheは呼び出した時の「m」だが
Clojureuの場合、checkloop 内の「m」は最初に実行された時のまま変わらない
この理解で正しいかは、ちょっと不安・・・
間違いがあったら教えて偉い人
m(_ _)m
追記:
ちなみに、こう書くとうまくいく
(defn problem5 [m] (defn checkloop [n s m] (if (= (mod n m) 0) n (checkloop (+ n s) s m))) (if (= m 1) m (let [newm (problem5 (- m 1))] (checkloop newm newm m))))
追記2:
loop,recurを使ってみた・・・
(defn problem5 [m] (if (= m 1) m (let [newm (problem5 (- m 1))] (loop [n newm s newm] (if (= (mod n m) 0) n (recur (+ n s) s))))))
確かに、便利かも「loop,recur」