2007년 1월 2일

팩토리얼을 구하는 스킴 스크립트

스킴(Scheme)이라는 프로그래밍 언어를 심심풀이로 배우고 있습니다. 상당히 깔끔한 언어라는 생각이 듭니다. 특히 알골 계열의 언어에만 길들었다면 처음 코딩할 때의 기분이 상당히 새롭습니다.

새로운 언어를 배우면 무언가 만들어 봐야 하기 때문에 차례곱을 구하는 프로그램을 작성하여 보았습니다. 실제로 차례곱을 구하는 부분은 5줄이지만 다른 부분이 대부분을 차지하고 있네요. MzScheme의 구현을 사용하여 스크립트 파일을 만들어 보았습니다. 맨처음으로 작성한 프로그램이라서 깔끔하지 못합니다. 여러 개의 숫자를 인자로 받거나 표준 입력으로부터 받아서 그 차례곱을 표준 출력으로 출력합니다. 이 프로그램을 /usr/local/bin에 넣어 두었습니다. 이제 차례곱을 쉽고 편리하게 구할 수 있겠습니다.

연습삼아 작성한 것이어서 재귀, letrec, do를 모두 한 번씩 사용해 보았습니다. 이번에는 가장 핵심적인 차례곱을 구하는 부분은 다음과 같이 재귀적으로 되어 있습니다.

(define fact
  (lambda (x)
    (if (= x 0)
        1
        (* x (fact (- x 1))))))

스킴을 처음 보시는 분도 위의 코드는 이해하실 수 있으리라고 생각합니다. 다음은 전체 프로그램의 소스 코드입니다.

#!/usr/bin/mzscheme -r
;;; Prints out factorial of given numbers.
;;; Date: 2nd of January, 2007

;; Returns factorial of given parameter.
(define fact
  (lambda (x)
    (if (= x 0)
        1
        (* x (fact (- x 1))))))

;; Prints out help message
(define help
  (lambda ()
    (display "Usage: fact [--help | [NUMBER]...]")
    (newline)
    (display "Calculate factorial of given numbers.")
    (newline)
    (display "If no numbers are given, it reads numbers from standard ")
    (display "input until EOF and prints each factorials of them.")
    (newline)
    (newline)
    (display "--help   display this message")
    (newline)
    (exit)))

;; Main procedure.
(define main
  (lambda ()
    (let ((number-of-args 
          (vector-length (current-command-line-arguments))))
      (if (and (= number-of-args 1)
               (equal? "--help" 
                 (vector-ref (current-command-line-arguments) 0)))
        (help))
      (if (= number-of-args 0)
        (begin
          (do ((number (read) (read)))
            ((eof-object? number))
            (display (fact number))
            (newline)))
        (letrec ((iter
                  (lambda (counter)
                    (if (< counter number-of-args)

            (begin
              (display (fact
                        (string->number
                          (vector-ref
                            (current-command-line-arguments)
                            counter))))
              (display #\space)
              (iter (+ counter 1)))))))
      (iter 0))))
    (newline)))

(main)

댓글 없음: