Posted by 大山
Sat, 24 Feb 2007 07:20:00 GMT
[참고: 이 글은 함수형 프로그래밍 1 - 함수 합성에 이어지는 시리즈임.]
앞 글에서는 두개 이상의 함수를 합성하여 새로운 함수를 만드는 방법을 살펴보았다. 이번 글에서는 함수에서 일부 인자의 값을 고정하여 새로운 함수를 만드는 커링(Currying) 기법을 다뤄본다. 우선 다음의 함수를 살펴보자.
f(x, y) = x^2 + y^2
g(y) = f(0, y) = y^2
위에서 함수 f는 x, y 두개의 인자를 가지는 함수이다. 함수 g는 함수 f에서 첫번째 인자의 값을 상수로 고정시켜 만든 새로운 함수이다. 이처럼 함수 f에서 일부 인자의 값을 상수로 고정시켜 새로운 함수 g를 만드는 과정을 커링이라고 부른다. (그래프로 보면, z = y^2 그래프의 모습은 z = x^2 + y^2 그래프와 x = 0 그래프가 만나는 단면의 모습이다.)
루비에서 함수 f, g는 다음과 같이 정의할 수 있다.
f = lambda {|x, y| x**2 + y**2}
g = f[0]
하지만 실제로 위의 코드를 실행하면, 두번째 줄에서 함수 f의 인자 개수가 틀리다는 에러가 발생하게 된다. 루비의 함수 호출은 커링 기능을 지원하지 않기 때문이다. 루비에 커링 기능을 추가하기 위해서는 다음의 코드가 필요하다. (이 코드는 Proc 클래스의 [ ] 메소드를 새롭게 정의하고 있다.)
class Proc
def [](*a)
if arity > a.size
lambda {|*b| self[*(a+b)]}
else
self.call(*a)
end
end
end
이제 irb에서 실제로 코드를 입력해보자.
>> class Proc
>> def [](*a)
>> if arity > a.size
>> lambda {|*b| self[*(a+b)]}
>> else
?> self.call(*a)
>> end
>> end
>> end
=> nil
>> f = lambda {|x, y| x**2 + y**2}
=> #<Proc:0x010abc10@(irb#1):10>
>> g = f[0]
=> #<Proc:0x010af310@(irb#1):4>
>> f[0, 5]
=> 25
>> g[5]
=> 25
Posted in 루비 | Tags 루비, 커링, 함수형 프로그래밍 | 6 comments | no trackbacks
Posted by 大山
Sun, 04 Feb 2007 14:20:00 GMT
함수형 프로그래밍이란 함수를 연산의 대상으로 삼는 프로그래밍 패러다임을 말한다. 수학의 함수를 떠올리면 되는데, 우선 다음의 예를 살펴보자.
f(x) = x + 3
g(x) = x^2
h = g * f
위에서 함수 h는 함수 f와 g를 합성한 새로운 함수이다. 이제 함수 h는 다음과 같게 정의된 것이나 마찬가지이다.
h(x) = g(f(x)) = (x + 3)^2 = x^2 + 6x + 9
루비는 객체지향 언어지만, 동시에 함수형 프로그래밍 언어이기도 하다. 이제 루비에서 함수 f와 g를 정의한 후, 이를 합성하여 함수 h를 만드는 과정을 살펴보도록 하자. 루비에서 함수를 정의할때는 lambda란 메소드를 사용한다. (여기에서 말하는 함수란 물론 Proc 객체를 말한다. 일반 메소드와 구분하기 위해 여기에서는 함수라는 표현을 사용하고 있다.)
f = lambda {|x| x + 3}
g = lambda {|x| x ** 2}
이제 함수 f와 g를 결합할 차례인데, 이를 위해서는 다음의 코드를 먼저 선언해 주어야 한다. [1]
class Proc
def *(func)
lambda {|*a| self[func[*a]]}
end
end
위의 코드는 함수 간의 연산인 *를 정의하는데, 이 연산이 바로 함수를 합성하는 연산이다. (위의 코드는 Proc 객체에 * 메소드를 추가하고 있다.) 이제 루비에서 다음과 같은 코드를 작성할 수 있게 된다.
이제 irb에서 실제로 코드를 입력해보자.
>> class Proc
>> def *(func)
>> lambda {|*a| self[func[*a]]}
>> end
>> end
=> nil
>> f = lambda {|x| x + 3}
=> #<Proc:0x0051d3f8@(irb):6>
>> g = lambda {|x| x ** 2}
=> #<Proc:0x0051a978@(irb):7>
>> h = g * f
=> #<Proc:0x0051ff2c@(irb):3>
>> f[2]
=> 5
>> g[5]
=> 25
>> h[2]
=> 25
위에서 'f[2]'는 루비에서 함수를 호출할때 사용하는 방식이다. 이 표현 대신 'f.call(2)'를 사용하는 것 또한 가능하다.
관련글: 함수형 프로그래밍 2 - 커링
Posted in 루비 | Tags 루비, 함수형 프로그래밍 | 12 comments | no trackbacks
Posted by 大山
Sat, 14 Oct 2006 17:49:00 GMT
오늘은 실용적 함수형 프로그래밍 세미나에 다녀 왔다. 대안언어축제 2006에서 같은 방을 사용했던 유재명님이 '다시 보는 디자인 패턴' 그리고 'Parsec 사용법 가이드'라는 주제로 발표를 하셨는데, 역시 Haskell은 매력적인 언어라는 생각이다. 대안언어축제때 재명님께 pair로 가르침을 받은 덕분에 이제 왠만한 Haskell 코드는 대강 이해가 가더라는~ :D
얼마전에 Mark Dominus가 1972년의 디자인 패턴이라는 글에서 디자인 패턴 무용론을 주장하여 한동안 영어권 웹에서 논쟁이 후끈 달아오르기도 했지만, GoF 책에 소개된 디자인 패턴 중 상당수가 자바나 C++의 언어적 제약을 극복하기 위해서 고안된 것만은 분명해 보인다. '다시 보는 디자인 패턴'은 Haskell과 같은 함수형 프로그래밍 언어에서 어떻게 많은 디자인 패턴이 패턴이라는 이름이 무색할 정도로 손쉽게 코딩될 수 있는 지를 잘 보여주는 발표였다.
두번째 발표였던 'Parsec 사용법 가이드'도 무척 흥미로웠는데, Parsec 같은 라이브러리만 있으면 왠만한 파서의 구현은 무척 간단한 작업이라는 생각이 들었다. 루비 코드 파서를 구현해보는 것도 그리 어려운 일은 아닐듯.
Haskell이 메인스트림 언어가 되지는 못할 것이라는 재명님의 언급이 있었지만, 길게 내다보는 개발자라면 함수형 프로그래밍 언어 한둘은 익혀야 한다는 생각이다. 멀리가지 않고 루비만 제대로 익히려 해도, 함수형 언어의 개념들이 필수적이다. 이론적인 것을 좋아하는 사람이라면 Haskell, 쉽게 배우고 싶다면 Lisp, 실무에 활용하고 싶다면 OCaml 등을 공부해 보는 것은 어떨까?
다른 약속이 있어서 마지막 발표인 'C++ 함수형 프로그래밍'은 참석하지 못했다. 다소 아쉽긴 했지만, 이건 다른 분들의 후기를 참고해야 할듯.
Posted in 프로그래밍 | Tags 디자인 패턴, 함수형 프로그래밍, Haskell | 4 comments | no trackbacks