関数内に補助関数を作り、その中で親関数の引数を利用した場合の挙動の比較

Project EulerProblem-5Clojureに移植していたらハマった・・・

Scala

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

Scheme(Gauche)版

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

Clojure

(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

挙動の理解はこう・・・
 ScalaGaucheは呼び出した時の「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」