UP | HOME

하스켈 맛보기

Table of Contents

탄탄한 타이핑을 갖춘 뻥셔널 정적 언어를 하나쯤은 써보고 싶다.

1. Aizu 하스켈로 풀어보기

1.1. main

하스켈의 엔트리 포인트는 Main 모듈의 main 함수이다. main 함수의 타입은 IO 액션이다.

module Main where

main :: IO ()

main 함수의 타입이 IO ()이기 때문에, IO ()를 반환해야한다. IO ()를 반환하는 다른 함수를 호출하거나, 명시적으로 IO ()를 반환해야한다.

-- Hello, World
main = putStrLn "Hello, World"

-- 아무것도 안 하는 프로그램
main = return ()

IO ()가 뭐냐? 앞의 IO는 뒤의 값이 IO라는 맥락 내에 존재한다는 것을 의미한다. 뒤의 ()는 값이 없음을 의미한다.

1.2. 입출력하기

하스켈 프로그램은 아무것도 import 하지 않아도 Prelude라는 라이브러리를 불러온다. 여기에 기본적인 입출력 함수도 정의되어 있다.

Prelude

대부분의 출력 함수들은 String을 인자로 취한다. String 외의 타입을 출력하려면 String으로 변환할 필요가 있다. Show의 인스턴스라면 show 함수로 쉽게 String으로 변환할 수 있다.

대부분의 출력 함수들은 딱히 반환하는 값이 없기 때문에 IO () 타입을 반환한다. 입력 함수들은 IO 장치로부터 특정 값을 얻어와야 하기 때문에 IO String, IO Char 따위의 타입을 가진다. 앞서 얘기한 것처럼, IO StringIO라는 맥락 내에서 쓸 수 있는 String 타입이다.

getContents :: IO String

getContents 함수가 특이한데, 모든 유저 입력을 받아서 하나의 문자열로 반환하는 함수이다. 게으르게(lazy) 동작한다고 적혀있는데, 실제로 필요할 때가 되어서야 데이터를 읽어들이고, 한 번에 모든 것을 읽지 않고 필요한 만큼만 읽는다는 뜻이다. 아래 프로그램은 map으로 String을 문자 단위(Char)로 쪼개어 처리하므로, 논리적으로는 전체를 가져와 한 번에 처리하는 것처럼 보이지만 실제로는 필요한 만큼만 처리를 하고 있다.

main :: IO ()
main = do
│ contents <- getContents
│ putStr (map toUpper contents)

실제로는 입력이 보통 줄 단위로 버퍼에서 전달되므로, 엔터를 입력할 때마다, 글자마다 처리가 되어 출력되므로

interact :: (String -> String) -> IO ()
interact f = do
│ contents <- getContents
│ putStr (f contents)
│
main = interact (map toUpper)

2. 참고자료

Author: 안녕

Created: 2024-12-10 Tue 22:08