functional programming을 하면 이런 느낌이 드는 것이 맞는 것인가?

2013-08-22 10:55

몇 일 동안 강의 준비 때문에 짬짬이 functional programming을 하면서 몇 가지 느낀 점이 있어 공유해 본다. 많은 경험을 한 것이 아니라 몇 일 동안 신용 카드의 LUHN 공식을 functional programming으로 구현해 본 정도이기 때문에 틀렸을 수도 있다. functional programming을 위한 언어는 Scheme을 사용했다.

LUHN 공식

신용 카드상의 번호 검증을 위해 사용하는 알고리듬. 1960년대에 개발된 개방형 공식이다. 원리는 ㉠카드 번호의 우측 숫자부터 매 2번째 숫자마다 2를 곱하고, ㉡위 ㉠에서 2를 곱하지 않은 숫자들과 ㉠에서 나온 숫자들을 합한다(㉠에서 나온 수가 2자리 수이면 2개의 숫자를 합한다). ㉢위 ㉡에서 나온 수와 그 다음으로 큰 10단위 수와의 차이를 구한다(㉡에서 나온 수가 34이면 다음으로 큰 10단위 수 40과의 차이, 6을 구한다). ㉢에서 나온 숫자가 카드의 점검 숫자와 일치해야 한다.

느낀 점

  • 작년인가 LUHN 공식을 자바로 구현한 경험이 있는데 그 때의 코드와 비교해 보니 소스 코드가 무지 간결해졌다.
  • functional programming으로 구현하다보니 요구사항을 작은 단위로 분리할 수 밖에 없었다. 자바로 구현할 때도 최대한 작은 단위로 분리해 메소드로 분리하는 작업을 했는데 functional programming은 의도하지 않아도 그렇게 할 수 밖에 없었다. 즉, 사고의 단위를 작은 단위로 줄여줌으로써 한 번에 한 가지에 집중할 수 있었다.
  • 작은 단위로 분리한 이유도 있지만 funtion 활용하니 단위 테스트하기 명확해서 좋았다. LUHN 공식이 어쩌면 입력과 출력이 분명해서 일 수도 있겠다. 하지만 객체 지향 언어보다는 단위 테스트하기 훨씬 좋겠다는 생각이 들었다.
  • 아직까지도 요구사항을 받으면 작은 단위로 분리해 문제를 해결하는 것이 쉽지 않다. 자바의 경우에는 은연 중에 큰 단위로 접근하는 경우가 많은데 functional programming의 경우 작은 단위로 분리하는 연습을 하기에 좋겠다는 생각이 든다. 프로그래밍을 처음 접하는 친구들도 functional programming을 활용해 문제를 작은 단위로 나누고 단위 테스트하는 연습을 하면 좋겠다는 생각을 했다.
  • 따라서 자바 프로그래머도 functional programming으로 연습해보면 자신이 개발하는 스타일을 바뀔 것이라 생각한다. 객체를 만들더라도 좀 더 immutable한 객체를 만드는 연습이 될 듯 하다.

이상 지금까지 functional programming의 맛을 제대로 느낀 것은 아니지만 앞으로도 계속 해보고 싶다는 생각이 들었다.

내가 느낀 부분 이외에도 functional programming을 통해 배울 수 있는 점이 있다면 공유해 주면 좋겠다. 앞으로 프로그래밍을 배워나가는 학생들에게 많은 도움이 될 듯하다.

이번에 Scheme으로 구현한 LUHN 공식 소스는 다음과 같다. 정확하게 구현했는지 모르겠다. 버그가 있으면 가차없이 신고 바람...

(define (charToDigit char)
    (- (char->integer char) (char->integer #\0)))
 
(define 
    (stringToDigit values)
    (map 
        (lambda (each) (charToDigit each)) 
        values      
    )
)
(define
    (doubleValue values)
    (map 
        (lambda (each) (* 2 each))
        values
    )
)
 
(define (ret-odds lst)
  (cond ((null? lst) lst)
        ((null? (cdr lst)) lst)
        (else (cons (car lst) (ret-odds (cddr lst))))))
 
(define (ret-evens lst)
  (cond ((null? lst) lst)
        ((null? (cdr lst)) (cdr lst))
        (else (cons (cadr lst) (ret-evens (cddr lst))))))
 
(define 
    (list-sum list)
    (cond 
        ((null? list) 0)
        ((null? (cdr list)) (car list))
        (else (+ (car list) (list-sum (cdr list))))
    )
)
 
(define (sum-over-ten value)
    (list-sum (stringToDigit (string->list (number->string value))))
)
 
(define (convert-two-to-one values)
    (map (lambda (each) 
            (cond
                ((< each 10) each)
                (else (sum-over-ten each))
            ))
        values
    )
)
 
(define (next-ten-value value)
    (+ 10 (- value (remainder value 10)))
)
 
(define (subtract-next-ten-value value)
    (- (next-ten-value value) value)
)
 
(define (calculate-validate-creditcard creditcard-no)
    (subtract-next-ten-value (list-sum (append
        (convert-two-to-one (doubleValue 
            (ret-evens (reverse 
                (stringToDigit (string->list creditcard-no))
            ))
        ))
        (ret-odds (reverse (stringToDigit (string->list creditcard-no))))
    )))
)
 
(calculate-validate-creditcard "5678222233334444")

0개의 의견 from FB

9개의 의견 from SLiPP

2013-08-22 13:10

나도 요즘 관심을 가지고 좀 보고 있다. JDK8.0부터 Lambda도 지원한다고 하고(근데 이거 release가 내년이라더군..) Spring4.0도 덕분에 지연되고 있는듯... spring4.0도 이러한 영향으로 많이 변할 듯 한데..

요즘 '자바 개발자를 위한 함수형 프로그래밍' 이란 책을 보고 있는데 좀 어렵네...ㅠ.ㅠ (이건 ebook밖에 없더라.)

2013-08-22 15:03

@jhindhal.jhang 내가 '자바 개발자를 위한 함수형 프로그래밍' 책 주문했는데 책이 오지를 않는다. 책이 ebook 밖에 없다면 절판 된건가? 근데 왜 주문이 되는 거야. 수업에 쓰려고 주문했는데 아직 오지도 않고 있다. 내일 수업인데...

2013-08-22 15:10

@자바지기 얼래 처음부터 ebook으로 나온거 아니냐? 원서는 있기는 한데 번역서는 ebook으로만 나온거 같은데?? 혹시 결제 했다면 한빛 사이트 가서 확인 해봐라..... 거기 ebook 부분에서 pdf로 널 기다리고 있을수도...

2013-08-23 12:08

카드번호로 카드회사 구분까지 해보셔야 고차함수의 매력을 느낄 수 있으실텐데 하하하.

계산 방식이 약간다르지만... 스킴이 제공하는 함수들을 활용하면 짧게 쓸 수 있습니다.

https://bitbucket.org/EP/kata/src/e22405060bfb4c6caf87fb8820b9406efffb3846/ProgrammingErlang/credit-card.ss?at=default

(require srfi/1)


(define (digit->integer c)
  (- (char->integer c) (char->integer #\0)))


(define (luhn-checksum ccn)
  (remainder
   (apply + (map (lambda (d i)
                   (let ((p (* (digit->integer d) (+ 1 (remainder i 2)))))
                     (+ (quotient p 10) (remainder p 10))))
                 (reverse (string->list ccn))
                 (iota (string-length ccn))))
   10))


(define (luhn? ccn)
  (eq? 0 (luhn-checksum ccn)))
  
(require rackunit)
(check-eq? (luhn-checksum "1") 1)
(check-eq? (luhn-checksum "12") 4)
(check-eq? (luhn-checksum "80") 7)
(check-eq? (luhn? "34") true)
(check-eq? (luhn? "123") false)
2013-08-23 12:28

@eungju.park.1 와 정말 짧게 구현할 수 있네. 역시 이런 수업은 functional programming 경험이 많은 친구들이 가르쳐야 되는데..

srfi/1은 라이브러리인가? rackunit 정말 단순한데. 난 test-manager (http://web.mit.edu/~axch/www/test_manager.html)) 활용했는데 은근 코딩량도 많고 짜증나던데.

내가 아직 let을 사용해 보지 않아서 그 부분도 함 공부해 보고 싶네. 네가 공유한 소스 코드는 수업 마지막에 함 공유해야겠다. 감사.

2013-08-23 16:26

@jhindhal.jhang 오늘 책이 왔다. eBook만 있는 것이 아니라 종이 책으로도 있는데. 근데 정말 책이 작고, 분량도 많지 않네. 하지만 이와 관련한 수업은 좀 전에 끝났다는거..

하나의 언어를 정말 짧은 시간에 공유한다는 건 쉽지 않은 일 듯하다.

2013-08-24 22:27

@자바지기 SRFI(Scheme Requests for Implementation)는 자바로 치면 JSR 이랑 비슷합니다.

rackunit은 Racket에서 제공하는 라이브러리입니다. Racket에 왠만한 라이브러리들은 다 있어서 저는 Racket 문서 찾아보고 있으면 그냥 써요.

2013-08-25 15:36

저는 작년부터 Scala언어만 공부하고 있는데 자바를 좀 오래했던지라 아직까지도 개념이 명확하게 와닿질 않네요 역시 많이 쳐보는것이 답인것 같습니다. 혹시 함수형 프로그래밍을 연습할때 좋은 예제문제나 과제 같은걸 모아놓은 사이트 같은것이 있다면 추천좀 부탁드릴게요..

2013-08-25 15:41

@이도현 저도 functional programming 관심 가지고 scala도 공부해 보고 했는데요. 지속성을 가지지 않다보니 생각의 전환이 잘 안되더라고요.

그러다 이번에 강의 때문에 scheme으로 프로그래밍 좀 해봤는데 scala 할 때 보다는 좀 더 느끼는 바가 많았던 듯 합니다. 짬짬이 "컴퓨터 프로그램의 구조와 해석 1" 책 보고 있는데요. 나름 생각하는 연습을 하는데는 괜찮은 듯 합니다. 단, 책이 엄청 어려워서 왠만한 인내력을 가지고는 진도가 잘 나가지 않더라고요. 그래도 이왕 하실 거면 이 책 한번 도전해 보는 것도 좋을 듯 합니다.

이렇게 어려운 책은 스터디 그룹 만들어서 해보시는 것도 좋은 듯 합니다. 그럼 어떻게든 서로 도와가면서 끝까지 하게 되더라고요. 아무래도 혼자하는데는 한계가 있는 듯 합니다. 이 책에 보면 연습 문제도 많고 나름 step by step으로 설명하고 있어서 괜찮은 듯요. 하지만 아직 1권의 반도 못봤는거 ㅋㅋ.. 느리긴 하지만 천천히 끝까지 가보려고요.

저도 시작한지 얼마되지 않아서 좋은 곳을 추천해 드리지는 못하겠네요. 아마도 @eungju.park.1 친구가 functional programming에 경험이 많아서 좋은 정보 공유해 주리라 기대합니다.

의견 추가하기