한국 하스켈 모임

두 번째 모임

하스켈 모임의 두 번째 오프라인 모임은 2015년 3월 18일 (수요일) 18시 30분에 한양대학교 서울캠퍼스 IT/BT관 501호에서 열렸습니다. 모임 목표는 “하스켈을 써본 경험이 거의 혹은 전혀 없이도 하스켈로 실제 코드를 짜서 현실적인 문제 해결을 해보는 것”이었습니다.

이 모임에서는 키노루가 하스켈에서 파일 처리를 시도하여 파일을 읽고, 이해하고, 파일을 쓰는 프로그램을 만드는 과정을 소개하고 이것을 모두 함께 실습함으로써 하스켈이 어떤 실용적인 용도로 사용될 수 있는지 체험해 보았습니다.

{-# LANGUAGE OverloadedStrings #-}

import Control.Monad (forever)
import qualified Data.ByteString as B
import System.IO
import System.IO.Error

main :: IO ()
main = do
    B.putStrLn "Processing ..."
    withFile "input.txt" ReadMode $ \ ihdl ->
        withFile "output.txt" WriteMode $ \ ohdl ->
            untilIOError (selectiveTransfer ihdl ohdl)
    B.putStrLn "Done!"

selectiveTransfer :: Handle -> Handle -> IO ()
selectiveTransfer input output = do
    line <- B.hGetLine input
    if "system:" `B.isPrefixOf` line
        then B.hPutStrLn output line
        else return ()

untilIOError :: IO a -> IO ()
untilIOError action = catchIOError (forever action) (\_ -> return ())

이 코드의 핵심 알고리즘은 selectiveTransfer 함수에 들어 있습니다. 이 함수는 파일 핸들 두 개를 인자로 받아서, 입력 핸들에서 한 줄을 읽어들인 뒤 (B.hGetLine input) 그 줄이 특정한 바이트열로 시작하면 ("system:") 출력 핸들로 내보내는 (B.hPutStrLn output line) 역할을 합니다.

굳이 이 코드를 최초의 하스켈 코드로 사용한 의도는 이렇습니다. 첫째로 파일을 열고 특정한 문자열로 시작하는 줄만 찾아서 복사한다는 것은 일상 생활에서도 흔히 필요할 수 있는 일이기 때문에 하스켈의 실용적인 쓸모를 느낄 수 있는 최소한의 예제를 구성하고자 했습니다.

둘째는 하스켈이 다른 프로그래밍 언어들과 사뭇 다르지도 않고, 또 배우기 위해서는 완전히 새로운 전산학 과목을 배우는 것처럼 노력을 들여야 하는 것도 아니라는 점입니다. 예를 들어 위의 코드와 같은 역할을 하는 파이선 코드를 짜 보면, 코드의 어느 부분이 어떤 역할을 하는지에 대해 일대일 대응이 가능할 정도입니다.

def main():
    with open('input.txt', 'r') as fin:
        with open('output.txt', 'w') as fout:
            while True:
                try:
                    selectiveTransfer(fin, fout)
                except EOFError:
                    break

def selectiveTransfer(fin, fout):
    line = fin.readline()
    if line == '':
        raise EOFError
    if line.startswith('Sheldon:'):
        fout.write(line)

if __name__ == '__main__':
    main()

일반적으로 하스켈에 대해서는 순함수형 언어라는 이유로 순수성(purity), 참조 투명성(referential transparency)이 강조되기 때문에 하스켈을 초심자에게 설명할 때에는 입출력 등 부작용이 있는 작업을 되도록 회피하려는 경향이 있습니다. 하지만 실제로 하스켈로 입출력을 짜 보면 다른 언어에 비해 어려운 것도 아니고 복잡한 것도 아니고 모나드나 타입클래스 이론을 알아야 되는 것도 아니라는 점, 즉 “하스켈, 어렵지 않다”를 강조하고자 했습니다.