letrecで繰り返す

Project EulerのProblem3をやった。
問題は素因数分解で、最大の素数を求めるもの。
素数を求めて割り切れるか確かめていけばいいだけだ。実に簡単…、じゃなかった。
分解する数が600851475143と超でかい。intじゃ収まらない。と思ったら、Lisp系の言語は多倍長演算してくれるようなので問題なかった。

素因数分解の方法としては、小さい素数から順次割り切れるかどうか確かめていく。割り切れれば、その商を割る数にして処理を継続する。素数が商以上になれば終了。てな感じである。

letrecを覚えたので使ってみた。

; 素数か?
(define prime-number?
  (lambda (m)
    (if (< m 2)
	#f
	(letrec ((find-prime
		  (lambda (i n)
		    (if (< i 2)
			#t
			(if (= 0 (remainder n i))
			    #f
			    (find-prime (- i 1) n))))))
	  (find-prime (- m 1) m)))))

; x以下の素数を求める
(define prime-below-x
  (lambda (x)
    (letrec ((rec-func
	      (lambda (i)
		(if (< i 2)
		    2
		    (if (prime-number? i)
			i
			(rec-func (- i 1)))))))
      (rec-func x))))

; 問題を解く、素因数分解
(define problem3
  (lambda (x)
    (letrec ((rec-func
	      (lambda (i x)
		(let ((p (prime-below-x i)))
		  (if (<= x p)
		      p
		      (if (= 0 (remainder x p))
			  (rec-func (+ i 1) (/ x p))
			  (rec-func (+ i 1) x)))))))
      (rec-func 2 x))))

答えは6857
(prime-number? 6857)
は#tを返したので、確かに最大の素数のようだ。