이 글에서 글쓴이는 하스켈을 배우면 좋은 점 몇가지를 제시한다. 첫 번째는 데이터를 먼저 생각하는 연습을 할 수 있어 전반적인 코딩 능력을 향상시킬 수 있다는 것이다. 두 번째는 하스켈이 가독성도 좋고 문제에 집중할 수 있게 해주는 언어라 하스켈로 개발을 하면 생산성이 높다는 것이다. 이 글을 보고 예전에 배우려다 포기했던 하스켈에 다시 도전해보고 싶은 마음이 생겨 공부해보았다. 목표는 이 알고리즘 문제를 푸는 것으로 설정했다.
예전에 공부할 때에도 느꼈고, 이번에 공부할 때에도 느끼는 거지만 하스켈에는 지금까지 배워본적 없던 새로운 개념이 너무 많다. 그리고 더 절망스러운건,
메인 함수
의 형태를 이해하려면 이 새로운 개념들을 거의 다 이해해야 한다는 것이다. Type system, IO, Functor, Applicative Functor, Monad.. 물론 이해하지 않고도 다른 코드들을 흉내내면 여차저차 코딩을 할 수 있겠지만, 그러면 배우는 의미가 없을 것 같아 우선 개념의 큰 덩이들을 이 교재를 통해 빠르게 습득하려고 노력했다. 그래도 양이 많아 시간이 오래 걸렸다. 하스켈 배우기를 더 빠르게 할 수 있는 방안이 무척 궁금하다.
큰 개념들을 모두 익히고 나서 세세한 부분 (어떤 generic함수를 사용해야 하는가. 함수의 형태는 어떤 것들이 있는가 등등)은 검색해가면서 문제를 풀어봤다. 그리고 나온 결과물이 놀라웠다. 일단 가독성이 정말 파이썬보다 훨씬 좋았다. 코드의 길이는 파이썬 코드보다 길어도,
재미없는 C++ 말고 하스켈로 풀어도 실행속도에서 걸리는 일은 없을 것 같다.
코드가 무엇을 하는지
를 안봐도 함수가 무엇을 하는 함수인지
가 한눈에 보였다. 또, 문제에 집중할 수 있다는게 이런걸 말하는 것인지, 아니면 단순히 운이 좋았던 것인지는 모르겠지만 예전에는 떠올리지 못했던 더 멋진 풀이법을 구해 문제를 해결할 수 있었다. 이 부분은 앞으로 몇 번 더 하스켈로 코딩을 해봐야 제대로 말할 수 있을 것 같다. 그리고, 실행속도가 파이썬의 실행속도의 오분의 일이였다. 앞으로 알고리즘 문제를 풀 때
실제 실무에서 쓸 기회가 있을지는 모르겠지만, 알고리즘 문제 풀 때에는 틈틈히 사용해봐야겠다.
결과물
import Control.Monad
readInt = do
input <- getLine
return $ (read input :: Int)
getInts = do
input <- getLine
return $ map (\n -> read n :: Int) $ words input
getDragonChar n
| n `mod` 6 == 0 = 'F'
| n `mod` 6 == 1 = 'X'
| n `mod` 6 == 2 = getDragonAt n
| n `mod` 6 == 3 = 'Y'
| n `mod` 6 == 4 = 'F'
| n `mod` 6 == 5 = getDragonAt n
getDragonAt n
| n `mod` 2 == 1 = getDragonAt ((n-1) `quot` 2)
| n `mod` 12 == 8 = '-'
| otherwise = '+'
main = do
n <- readInt
forM [1..n] (\_ -> do
_:begin:end:[] <- getInts
putStr $ [getDragonChar x | x <- [begin-1..begin+end-2]]
putStr "\n"
)