IO 프로그래밍을 위한 팁 7가지
참고 사이트: Haskell IO
하스켈은 참 멋진 언어입니다.
완벽에 가까운 타입 추론 기능에 기반한 '람다'나 '고차 함수'와 같은 세련된 함수 처리 기법들이나 패턴 매칭기법은 정말 처음 보는 사람을 '혹'하게 하는 하스켈만의 매력입니다.
그런데...
이런 멋진 놈으로 뭐 좀 해보려고 하면...뭔가 연습삼아 간단한 프로그램 좀 만들어 볼라치면 바로 좌절에 빠지고 맙니다. 바로 IO(입/출력) 처리 때문이죠...
네... 전 하스켈 참 멋진 언어라 생각합니다만 IO 처리에서 만큼은 정말이지 C++의 std::iostream 보다도 더 친하게 지내고 싶지 않은 놈이라 생각합니다. (하긴...하스켈의 모나드나 C++의 std::streambuf_iterator 나 그게 그놈이지만요...)
어쨌든 전 하스켈이 사람들에게 쉽게 다가가지 못하는 이유는 전적으로 기존의 튜터리얼 문서나 책들이 대부분 IO 를 공부할 때 하스켈 IO 작업의 이론적 기반이 되는 '모나드'라는 개념에 대한 이해를 강요하기 때문이라고 생각합니다. 때문에 기초적인 IO 예제를 만들기 위해서 사람들은 레벨도 낮은 초보시절부터 강력한 보스를 만나 고전하다가 뻗어버리곤 하죠...
따라서 우리가 C++를 공부할 때
std::cout << "Hello World" << std::endl;
이 라는 문장을 놓고 연산자 재정의나 함수 오버로딩, 템플릿 등등을 주저리주저리 설명하지 않듯이(아마 std::endl이 함수라는 사실을 모르고 사용하는 C++프로그래머들이 상당수일 것이라 생각합니다. 그리고 전 그게 그리 큰 문제라고 생각하지 않습니다.) 하스켈에서도 초보자를 위한 문서라면 어쨌든 1장에서 IO 사용법을 예제를 통한 주입식 방법으로 익숙하게 만든 다음 나중에 '모나드가 어쩌구...'라는 심화학습을 해야 한다고 생각합니다.
아마 저 위에 링크의 글을 쓴 사람도 그런 생각을 했나 봅니다. 어쨌든 IO 관련 작업은 이런식으로 해봐라...라는 주입식 규칙 7가지를 이야기하는 군요. 요약하자면 아래와 같습니다.(설명 및 소스는 제가 약간 첨언했습니다.)
규칙 1. - IO 작업이 포함된 함수는 do 로 시작해라...(여기서 do가 어떤 역할을 하는지 자세한 설명을 하면 큰일남!)
규칙 2. - import System.IO 를 추가해라 (C++로 따지면 #include <iostream>과 같음)
규칙 3. - 순수한 IO 작업만 하는 함수라면 리턴값 필요없다.
예) main = do putStrLn "Hello, World!!!"
규칙 4. - 만약 어떤 IO 작업 결과를 저장하고 싶으면 '<-' 를 사용해라
예) main = do
text <- getLine
putStrLn text;
규칙 5. - 만약 IO 작업이 아닌 순수 하스켈 함수 값을 저장하고 싶으면 'let' 을 사용해라. (물론 엄밀한 의미에서 저장하는 것이 아니지만 이 또한 지금 당장에 자세히 파고들 필요는 없습니다.)
예)
convertUpper = map Char.toUpper
main = do
text <- readFile "somefile.txt"
let upperText = convertUpper text
putStrLn upperText
규칙 6. - 만약 함수가 do로 시작했으면 마지막에는 IO 타입의 어떤 값을 리턴해야한다. 여기에는 아래와 같은 두 가지 방법이 있다.
6-1. IO 타입을 리턴하는 함수가 마지막에 오면 된다. 규칙 3,4,5의 예제가 이에 해당한다.
6-2. IO 타입이 아닌 어떤 값을 리턴하려면 return 문 다음에 리턴하고자하는 값을 쓴다. 예를 들어 규칙 5의 main함수는 다음과 같이 바꿀 수 있다.
myReadFile filename = do
text <- readFile filename
let upperText = convertUpper text
return upperText
main = do
text <- myReadFile "somefile.txt"
putStrLn text
규 칙 5의 main함수는 putStrLn 함수로 끝나는데 이 함수는 IO 타입을 반환하는 함수이므로 return이 필요없으며 바로 위의 myReadFile 함수는 upperText라는 값을 반환하므로 return upperText라고 했다. 만약 어떤 값도 리턴할 필요가 없으면 그냥 return () 라고 하면 된다.
규칙 7. - 모든 IO 작업마다 일일히 <- 를 하는게 귀찮을지 몰라도 그렇게 하는게 더 쉽다.(더 짧게 쓰려면 모나드를 이용해야 하는데 그건 나중에 생각하자.)
이 규칙만 잘 이해하면 기본적인 IO 작업하는데 큰 무리는 없을 듯 싶군요...
어쨌든 결론은 초보시절부터 '모나드'를 이해하려고 하면 안된다는 것! 그건 나중에 생각하자구요~ ^^
덧붙임 - 위 규칙들은 다음 순서대로 이해하시면 더 좋을 것 같습니다.
규칙2. import System.IO 추가
규칙1. 입/출력 작업이 있는 함수는 do로 시작
규칙6. do로 시작한 함수는 return으로 끝냄
규칙3. 단, 순수하게 IO작업만 하는 함수라면 return 생략 가능
규칙4. 입/출력 결과 저장 시 <- 사용
규칙5. 입/출력 값이 아닌 값을 저장하고 싶으면 let 사용
규칙7. 모든 작업은 한 줄에 한 작업씩...
History
Last edited on 03/31/2008 18:01 by gimmesilver
Comments (0)