{{|
|}}
1. Haskell의 소개 ¶
HaskellLanguage는 함수형(Functional) 패러다임을 기본으로 하는 언어이다. 다른 함수형 언어들인 LispLanguage, ML, Scheme등의 언어처럼 HaskellLanguage는 단순하다. 모든 표현 수단은 함수이며 함수는 정수와 같은 기본자료형(primitive data type)으로 취급된다. HaskellLanguage는 함수형 언어 중에서도 가장 순수한 언어이며 가장 진보된 언어 중의 하나이다. 현재는 Haskell 98이 표준이고, 새로운 표준인 Haskell'이 논의되고 있다.
2. 왜 Haskell인가? ¶
거대한 소프트웨어 시스템을 구성하는 것은 매우 어렵고 힘든 작업이다. 그 노력과 비용을 줄여주는 우수한 방법 중 하나는 함수형 프로그래밍 언어(Functional Programming Language)를 사용하는 것이고 그 중에서 Haskell은 유일한 Purely-Functional Programming Language이다.
- 단일한 알고리즘의 적용
함수형 언어는 자료의 형태와 상관 없이 알고리즘을 일반적인(Generic) 방법으로 프로그래밍이 가능하게 해서 생산성을 향상시킨다. 이러한 특성의 장점은 일반화 프로그래밍(Generic Programming)이란 이름으로 명령형(Imperative Programming Language)에서 받아들이고 있으며 CppLanguage의 STL을 써봤던 유저라면 쉽게 동의할수 있을것이다. 심지어 자바조차도Generic Java이란 이름으로 JDK1.5대 부터 함수형 패러다임의 일부를 수용할 계획이다.
아래의 함수 difSquare는 x,y가 어떤 형이든 받아들여 그 차를 제곱하여 반환한다 그리고 직관적이다.
difSquare x y = (x-y)^2
- 형을 유추하는 언어
HaskellLanguage를 처음 본 사람들은 형 검사가 느슨하거나 동적으로 형이 할당되는 언어처럼 보일것이다. 하지만 HaskellLanguage는 C++/C/JAVA보다 엄격한 형 검사를 가지고 있다. 하지만 Haskell은 Type Inference 엔진에 의해서 지능적으로 형을 추적한다. 어떤 경우에도 함수 그 자체의 형만 형 선언(type signature)으로 지정해주면 컴파일 과정(compile time)에 inference rule에 따라 가능한 일반적인 형을 추론해낸다.
Integer에 제약된 factorial 함수
fact :: Integer -> Integer fact n | n < 0 = error "negative integer" | n == 0 =1 | n > 0 = n * fact (n - 1)
일반화된 factorial 함수
fact n | n < 0 = error "negative integer" | n == 0 =1 | n > 0 = n * fact (n - 1)
일반화된 factorial 함수의 형 검사
:type fact 8.0 fact 8.0 :: (Ord a, Fractional a) => a :type fact 20 fact 20 :: (ord a, Num a) => a :type fact fact :: (Num a, Ord a) => a -> a
- 배정문이 없는 언어
배정문이 존재하지 않기 때문에 HaskellLanguage는 순수한 Purely-Functional Programming라고 부른다. 배정문은 메모리속에 "값"을 넣는 저차원 적인 연산이기 때문에 디버깅 과정은 귀찮은 "메모리 덤프"를 해야 하고 병행처리는 프로그래머를 미치기 한다 Haskell은 최신 기술인 State Monad를 이용해서 우아하게 배정문을 배제하고 있다.
예전에 Haskell에 관해 본적이 있는데 영어가 짧은탓인지 Monad가 무엇인지 잘 알수가 없었습니다. 가능하다면 설명 좀 해주세요.
저도 "개념"적으로 Monad를 완벽히 이해한게 아니라서 글로 설명하기는 힘들군요. Monad는 함수에서 함수로 정보를 전달하는 것 같은 느낌이 들었습니다. IO나 State Monad 등을 주로 문서에서 보셨을것 같습니다. 가변적인 "변수"값이 없이 "상수"처럼 취급된 데이터가 함수로 전달되어서 "메모리 덤프"등의 오류에서 벗어나게 한다고 하더군요. 일반적으로 쓰이는 Monad는 다음과 같은게 있습니다.
C언어 소스
int f1(float w) { const char x = g1(w) ; const double y = h1(w, x) ; const int z = i1(w, x, y) ; return z ; }
Monad를 사용하지 않은 소스
f1 w a = let (b, x) = g1 w a (c, y) = h1 w x b (d, z) = i1 w x y c in (d, z)
Monad를 사용한 소스
선언부분은 생략한채 소스를 붙였습니다.
f w = do x <- g w y <- h w x z <- i w x y return z
Monad를 사용한 소스는 특별한 표현없이 함수의 정보를 뒤의 함수에게 전달하게 되는 것 같습니다. 데이터 -> (출력) -> (출력) -> 출력 등의 형식으로 다단계로 정보를 내려보내는 것이 가능하더군요. 특히 이러한 기법들은 IO와 파일 입출력에서는 효과적으로 사용되더군요. 예외처리부분에서는 제대로 이해하지 못하였지만 그 분야에서 효율적으로 사용되어 지는 것 같습니다. 내공이 부족해서 부실한 답변을 드려서 죄송합니다. --씨엔
- 순환 구조의 언어
모든 for나 while의 반복구조는 순환(recursion)구조으로 대체할수 있고 순환구조는 반복구조보다 사람에게 편하다. 함수형 언어가 대게 그렇듯이 overflow없는 순환을 제공해주며 이것은 프로그램의 흐름을 간편하게 만들어 준다.
수를 세는 방식의 순환 구조
-- Factorial by primitive recursion on decreasing num fac1 :: Int -> Int fac1 n = if n==1 then 1 else (n * fac1 (n-1))
목록(list)를 이용한 순환 구조
-- Factorial by primitive recursion on list tail fac2 :: Int -> Int fac2 n = prodList [1 .. n] prodList lst = if (length lst)==1 then head lst else head lst*(prodList (tail lst))
- Lazy Evaluation
Haskell은 Lazy Evaluaion을 제공해서 프로그래머가 다루는 데이터의 범위를 무제한으로 만들어준다. 아래의 문장은 홀수의 전체를 의미하는 것이다. 이 문장은 어떠한 메모리상의 오류도 발생시키지 않는다. Haskell은 컴파일 할때(compile time)에 필요한 "일"만 적용시키기 때문에 어떤 범위의 자료들을 가지고 연산을 해도 오류가 생기지 않는다. (see also 필요한만큼만)
i=[1,3 ..]
- 함수를 함수로 넘기는 언어
함수형 언어 함수 조차도 기본 데이터 형으로 인식이 되기 때문에 함수와 함수의 결합이 자유로와서 표현력을 늘여 줍니다.
dubSqr2 함수는 square와 double을 결합한 형식의 함수이다.
square :: Int -> Int square n = n*n double :: Int ->Int double n = n*2 dubSqr2 :: Int -> Int dubSqr2 = square.double
- Haskell은 실용적인 언어이다.
함수형 패러다임은 다른 패러다임과는 달리 불필요한 성능의 장애를 일으키기 않고 범용적이기 때문에 가능한것이다. 함수형 프로그래밍 언어로 유명한 Lisp의 경우에는 어떠한 경우에도 C언어에 비해서 20%이상의 속도차이를 보이지 않았다고 하며 일부의 경우는 더 빠른 결과를 보였다고 한다. Lisp의 경우에는 C이전에 매우 많은 시스템 프로그래밍에서 범용성을 인정 받았다고 한다. 함수형 언어는 "실험실용"이나 "교육용"언어는 아니다. 그렇기 때문에 Microsoft도 Haskell으로 분산객체 시스템을 만드는 연구를 하고 있다. 실험실용 언어를 Microsoft가 투자하는 경우는 찾기 어려울 것이다.
- Haskell은 간결하다.
Haskell에서 모든 홀수와 짝수의 순서쌍을 만들고 싶다면 다음과 같이 입력하면 된다.
[ (x,y) | x <- [1,3 ..], y <- [2,4 ..]]
Haskell이 퀵소트를 일반화(Generic)해서 접근한 소스와 C언어의 소스를 비교하면 함수형 언어(Functional Programming Language)와 명령형 언어(Imperative Programming Language)의 간결한 문법과 문장을 느낄수 있을것이다.
Quicksort in Haskell
qsort [] = [] qsort (x:xs) = qsort elts_lt_x ++ [x] ++ qsort elts_greq_x where elts_lt_x = [y | y <- xs, y < x] elts_greq_x = [y | y <- xs, y >= x]
Quicksort in C
qsort( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }
5. 토론 ¶
제가 해보니 HaskellLanguage는 느리더군요. 그리고 LispLanguage는 빠릅니다. 제가 느끼기에 HaskellLanguage는 자바와 비슷한 속도를 내는 것 같더군요. 예제들 컴파일해보고 실행해 보면서 공부하다가 느리다는 것을 느끼고 그만두었습니다. LispLanguage가 빠르다고 해서 함수형 언어가 다 빠르다고 할 수는 없을 것 같습니다. 그래도 개념은 정말 좋은 언어같습니다. 저 같은 시스템 프로그래머가 접근하기는 좀 느리지만... 속도마저 빠르다면 HaskellLanguage는 최강일 것 같습니다. -_-)=b --RedPain
성급한 일반화를 했던 거군요. 아직 대규모의 프로젝트를 해본 적이 없어서 막연히 추측한 게 잘못된 결과를 낳은 것 같습니다. 어떤 컴파일러로 어떤 소스로 테스트 하셨는지 알 수 없을까요? 여러가지 테스트를 해가면서 성능에 대해서는 살펴볼 필요성이 있겠군요. --씨엔
저는 ghc를 linux 위에서 사용했습니다. 저도 대규모 프로젝트라고 할 만한 것까지는 안해봤습니다. 제가 어셈블리어와 CLanguage만을 사용하는 시스템 프로그래머라서 속도에 민감해서 느끼는 것 같습니다. 전 CppLanguage로 만들어도 속도가 느린게 조금 느껴지더군요. 흠...근데 사실 빠르다 느리다는 것은 상대적인 개념이니까 비주얼 베이직이나 JavaLanguage 쓰시는 분들은 저와는 다르게 생각하실 것 같습니다. --RedPain
HaskellLanguage는 실용적인 언어이다: Q) Then, is there any commercial quality software written in Haskell? --LispM
commercial quality정도에 부합될지는 모르겠습니다만 http://haskell.org/practice.html에 쓰여진 프로그램들이 있더군요. 널리 유명한 프로그램은 보이지 않는군요. 이 쪽을 보시는 편이 더 도움이 되실것 같습니다. Microsoft가 투자한다는 것 자체가 실용적인것이라고 생각이 되어서 글을 적었습니다. 최근에 Microsoft가 투자하는 언어는 ML, HaskellLanguage, PythonLanguage으로 알고 있습니다. --씨엔
That explains me why Lisp(Common Lisp) is faster than Haskell. In Lisp world, there are already plenty fo research/commercial products. That means returns(e.g. money) from such products can be used to improve Lisp systems. Also, Lisp is the second oldest language and still actively evolving. See also http://openmap.bbn.com/~kanderso/performance/ about peformance of Lisp. Microsoft and Apple once had Lisp systems as their product. And there is a big gap between research and real products. I guess Microsoft just(no more, no less) wants to play with ML, Haskell, Python, etc. --LispM
아직 HaskellLanguage는 신생언어이니 중견언어인 LispLanguage에 비해서 최적화 측면이나 실적에서 뒤떨어지는게 많은 것은 사실이겠죠. 그건 새로 시작한 언어라면 대개 비슷할 거라고 생각합니다. 실적은 앞으로 나오겠고 최적화는 앞으로 계속 이루어지겠죠. 최적화나 실적의 경우에 가장 뛰어난것은 고전적인 언어가 아닙니까? (실적과 최적화를 따진다면 포트란만한 언어를 찾긴 힘들겁니다.) 배정문이 없는 특성과 lazy evaluation등의 특징이 생산성을 향상시켜서 앞으로의 미래는 밝은 것이라고 생각합니다. --씨엔
최적화나 실적의 경우에 가장 뛰어난 것은 고전적인 언어가 아닙니까? (실적과 최적화를 따진다면 포트란만한 언어를 찾긴 힘들 겁니다.) This is not true. Languages like Fortran will make you live in their limits - Languages like Haskell or Lisp will make you free and evolving. I'm just thinking Haskell has to go long way to be a commercial quality programming language(like Lisp already did with a lot of mistakes and time consuming tasks). --LispM
몇번이나 이 페이지를 찾으면서 LispM님이 쓰신 답글을 읽었습니다만, 여전히 어떤 뜻으로 쓰신 글인지 잘 모르겠습니다. 위에서도 LispM님이 쓰셨듯이, Lisp는 오래된 언어이고, 씨엔님께서는 그런 점도 포함해서 Lisp가 충분한 최적화와 실적을 갖추게 되었다고 쓰신 것 같습니다만, LispM님의 두번째 답글은 어떤 부분에 대한 부정인지요?최적화나 실적의 경우에 가장 뛰어난 것은 고전적인 언어가 아닙니까? 부분은 아닌거 같습니다만, 후반부에 대한 부정이라면, 실적과 최적화라는 면에서는 부정할만한 부분을 찾기 어렵습니다. Fortran언어의 한계가 왔다는 점은 부정하기 힘들지만, 논의의 방향과는 좀 먼거 같습니다.--MiRiS
동의한표. 그나저나 LispM님은 우리와남을위해 한글로 명확한 의견을 표하는 게 더 낫지 않을까 싶습니다. 소수자 토론을 하는 게 목적은 아닐테니까요. (게다가 다큐먼트모드로 넘어갈 때 반드시 정리될 부분이기도 하구요) -- 아샬 2009-05-21 02:01:31
실질적으로 Lisp이나 Haskell이 실무에 사용되는 빈도 자체가 훨씬 적기 때문에, 아무리 언어 자체가 좋고, 다양하고 강력한 기능을 제공하고, 상용 솔루션으로 문제를 극복할 수 있다고 해도 이것이 단순히 돈을 벌기 쉽다고 말할 수는 없다고 봅니다. 기업에서는 프로그래밍 구현은 물론이고 유지보수도 신경을 써야 하는데, 이 때 가장 문제가 되는 것은 현재 돌아가는 프로그램을 적절하게 수정하고 유지보수를 할 수 있는 개발자를 얼마나 쉽게 구할 수 있는가 입니다. 역사가 긴 Lisp만 해도 사람 구하는 것이 결코 쉽지 않지요. 이러면 회사에서는 해당 언어 도입을 꺼릴 수 밖에 없게 됩니다. 돈이 있어도 사람을 못구해서 운영을 못할 수 있기 때문이죠. 게다가 Fortran은 Fortran 대로 전문적으로 쓰이는 분야가 있습니다. 그러한 분야에서 Fortran이 하던 일을 Lisp 이나 Haskell로 대체하는 것은 단순히 언어 뿐만이 아닌, Fortran이 수행하던 작업과 동등한 성능과 결과를 제공할 수 있는 라이브러리 또한 필요하게 됩니다. 만약에 없다면 직접 만들어야 하는데, 이는 시간과 비용 모두 위험 부담이 상당히 큰 모험이 됩니다. 이런 모험을 감수하고 직접 만드느니 있는 것을 그대로 굴리는 것이 일반적인 회사가 취할 입장 같네요. --daybreak 많은 수는 아니지만, 각종 Haskell을 사용한다는 회사들(규모가 그리 커보이지는 않는데도 연간 12000파운드, 1000파운드정도를 Haskell에 투자(?)하면서 활발하게 업무에 활용하지 않을리가 없다고 생각합니다.)은 시장 모니터링, 금융 모델 설계와 trading 관련이 상당수, mortage가 어쩌고, ERP system이 어쩌고 하는걸 보면 Haskell도 나름대로 적합한, 또는 필요로 하는 시장이 있는 것처럼 보입니다. ERP는 적합했는가 좀 의문스럽지만요. Haskell을 사용할 수 있는 인력을 도저히 구할 수 없는 경우를 위해서, Galois나 FP Complete 같은 회사들은 Haskell을 사용할 수 있는 인력을 제공하거나 (출장)교육을 제공하기도 하는걸 보면, 적어도 외국에서는 심각한 인력부족으로 인한 문제에 부딪히지는 않을지도 모르겠습니다. 물론 유지·보수를 위해서 교육까지해가면서 Haskell을 사용해야 할 메리트가 있는가는 중요하겠습니다만. 굳이 기존의 언어가 존재감을 발휘하고 있는 시장도 다 Haskell이 차지해야하는 것은 아니니까, 특정 목적을 위한 라이브러리가 다른 언어에 비해서 부족하다고 해서 Haskell 자체의 경쟁력 부족이라고 하기는 힘들 것 같습니다. 전산업계에서 공략해야 될 대상이 레거시 대체만은 아니지 않습니까? 물론 기계 전공 친구들은 고대 Fortran 소스를 '그대로' 사용하는 일이 있어서 조금 배우는데... 한편 제 지도교수님은 여전히 Lisp를 주력으로 사용하고 계시기에 전 다른 연구원들이 읽고 쓸 수 있도록 Java/Python등으로 번역해주지요. --MiRiS
마이크로소프트웨어에 haskell 연재를 하신 김재우님께서는 처음으로 배우는 언어로 HaskellLanguage을 추천하시더군요. 전 가끔 후배들에게 랭귀지를 가리키면서 그런 고민을 한 적이 있습니다. 과연 정말로 제대로 프로그래밍하는 재미를 알려면 어떤 언어를 처음선택하는 것이 좋은가 하는 점말이죠. 요즘 PythonLanguage를 공부하고 있는데 처음으로 이 언어를 배우면 어떨까 하는 생각도 듭니다. 일단 인터프리터 언어의 장점이라 할 수 있는 빠른 피드백이 초보에게는 바로바로 결과를 확인함으로써 성취감과 재미를 가져다 주지 않을까 하는 생각에서 입니다. --원광현
모든 엔지니어에게 첫 언어로 HaskellLanguage가 적합하다고는 생각하지 않습니다. 현존하는 컴퓨터들은 폰노이만 머신들이므로 HW 레벨부터 공부해온 엔지니어에겐 어셈블리나 C와 같은 폰노이만 언어들의 수순을 밟는 것이 자연스럽겠습니다. 수학과 같이 추상적 레벨부터 공부해온 엔지니어라면 또 다르겠지요. --또마
'모든 엔지니어'와 목적에 적합한 언어는 아니겠지만, 많은 프로그래머에게는 좋은 언어가 아닐까 생각됩니다. 물론, 하드웨어적인 면도 생각하지 않을 수는 없지만요. Joel on Software의 글에서도 C와 Haskell을 같이 배우는 것을 권하는 것처럼 읽혔습니다.(꼭 'C'와 'Haskell'이라는 것은 아니겠지요.) 서로 다른 출발점을 가지는 언어인만큼, 양쪽면을 배우는 것은 좋겠지요. 두가지면을 다 포함하는 언어도 있겠지만, 학습이라는 면에서는 더 고생이더라도 두 언어를 배우는 편이 더 좋다고 생각합니다.(솔직히 두가지 면을 다 가질 수는 있지만, 어떤 특성을 가지고 있는가가 확실하지 않은 언어는 설계된 본래의 목적에서 벗어나겠죠. --MiRiS