Skip to content

필사 모드: 모던 Haskell 2026 — GHC 9.10 / 9.12 / GHCup / Cabal 3.14 / Stack / IHP / Servant / Effectful / Pandoc / Cardano 심층 가이드

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 — 2026년에도 Haskell을 쓰는 사람들이 있다

매년 누군가는 묻는다. "Haskell, 아직도 써요?"

쓴다. 그것도 꽤 진지하게 쓴다.

- **GitHub**은 Semantic을 Haskell로 짰고, 코드 검색 일부 인프라가 그 코드 위에서 돈다.

- **Cardano**는 IOHK가 만든 Plutus 스마트 컨트랙트 플랫폼이고, 핵심 노드는 전부 Haskell이다.

- **Mercury Bank**, **Channable**, **Tweag**, **IOG**, **Standard Chartered**, **Anduril**, **Wire**, **Hasura**는 프로덕션 Haskell 코드베이스를 운영한다.

- **Pandoc** — John MacFarlane이 짠 문서 변환기는 학계와 출판계의 표준이다. 이 블로그도 마크다운에서 PDF로 갈 때 결국 Pandoc을 거친다.

- **Shellcheck**, **xmonad**, **darcs**, **postgrest**, **purescript**, **elm 컴파일러(2018년 0.19 기준)**, **dhall**, **agda**, **idris**도 Haskell이다.

2010년대 Haskell의 적은 "쓰기 어렵다"가 아니었다. 진짜 적은 **빌드 도구가 둘이고 — Cabal과 Stack — 둘 다 미묘하게 다른 방식으로 망가져 있다**는 것이었다. 그게 2026년에는 어떻게 되어 있을까.

답: **GHCup이 둘을 동시에 잘 관리한다**. 그래서 더 이상 "Cabal 파일을 받았는데 Stack 사람이 보내준 거라 안 빌드된다" 같은 일은 거의 없다. 그리고 GHC 자체도 9.10·9.12에서 한 단계 더 빨라졌고, 모듈식 컴파일과 다중 코어 활용이 개선되었다.

이 글은 2026년의 Haskell 스택을 한 호흡으로 본다. 컴파일러부터 빌드 도구, 풀스택 웹 프레임워크, 효과 라이브러리, ORM, 파서, JSON, 테스트, 정형 검증, ML, 문서 변환, 그리고 사람들까지.

1장 · 2026년 모던 Haskell — GHC 9.x의 시대

먼저 한 장의 풍경.

모던 Haskell 2026 스택

[설치] GHCup (권장) ── ghc / cabal / stack / hls

[컴파일러] GHC 9.10 (2024.5) / 9.12 (2024.12)

[빌드] Cabal 3.14 | Stack (LTS 22.x, Stackage)

[패키지] Hackage (전체) | Stackage (큐레이션 LTS)

[웹 풀스택] IHP (Rails 스타일, digitally induced)

[웹 API] Servant (타입드 HTTP DSL)

[웹 그 외] Yesod / Snap / Scotty / Spock

[효과] Effectful (mtl 대체, 2026 대세)

Polysemy / fused-effects / Bluefin

[ORM] Persistent / Beam / Esqueleto

[파서] Megaparsec / Attoparsec / Earley

[JSON] Aeson

[문자열·바이트] text / bytestring / vector

[테스트] hedgehog (property) / tasty / hspec / QuickCheck

[정형 검증] Liquid Haskell (refinement types)

[ML] Hasktorch (libtorch 바인딩)

[문서 변환] Pandoc (John MacFarlane)

[프로덕션 사용자] GitHub / Cardano / Mercury / IOG /

Hasura / Anduril / Channable / Tweag

이게 2026년의 Haskell 지형도다. 박스 하나하나 들어가 보자.

2장 · GHC 9.10 (2024.5) / 9.12 (2024.12)

GHC(Glasgow Haskell Compiler)는 Haskell 표준 구현이다. 사실상 유일한 산업용 구현이라고 봐도 무방하다.

GHC 9.10 (2024년 5월)

- **GHC2024 언어 에디션** — 1년 단위로 묶이는 언어 확장 묶음. 이제 `default-language: GHC2024`만 적으면 `LambdaCase`, `DataKinds`, `DerivingStrategies`, `DisambiguateRecordFields`, `ExplicitNamespaces`, `MonoLocalBinds`, `RoleAnnotations`, `ScopedTypeVariables` 등이 기본으로 켜진다.

- **Linear Types(`-XLinearTypes`)** 개선 — 함수형 자원 추적의 핵심.

- **GHC Proposals 511** — `let` 안에서 타입 시그니처를 더 자연스럽게 쓸 수 있다.

- **JavaScript backend** 안정화 — `wasm32` / `javascript` 백엔드가 정식 지원.

- **러닝타임 시스템(GC, threaded RTS)** 튜닝 — `-A` 기본값 변화, 64-bit 머신에서 콜드 캐시 성능 개선.

GHC 9.12 (2024년 12월)

- **CapiFFI calls** 개선 — C 헤더에서 가져온 매크로 함수와 더 안전한 인터페이스.

- **`OrPatterns` 확장** — 패턴 매칭에서 여러 생성자를 `|`로 묶을 수 있다.

- **`NamedDefaults`** — 타입 클래스의 기본 인스턴스를 명시적으로 선언.

- **`MultilineStrings`** — 따옴표 세 개 멀티라인 문자열, 다른 언어 사용자에게 친숙한 모양.

- **타입 추론 일관성** — 다형성 변수가 더 적게 모호해진다.

- **빌드 성능** — 약 5-10% 컴파일 시간 단축(평균치).

-- GHC 9.12의 MultilineStrings + OrPatterns 예시

{-# LANGUAGE MultilineStrings #-}

{-# LANGUAGE OrPatterns #-}

greeting :: String

greeting = """

Hello,

modern Haskell 2026.

"""

classify :: Int -> String

classify n = case n of

(0 | 1 | 2) -> "small"

(3 | 4 | 5) -> "medium"

_ -> "large"

어느 버전을 써야 하나

- **새 프로젝트**: GHC 9.10.x — 가장 균형 잡힌 선택. HLS·Stack LTS·IHP·Servant 모두 1급 지원.

- **모험가**: GHC 9.12.x — 새 문법(MultilineStrings, OrPatterns)을 원할 때.

- **엔터프라이즈/긴 의존성 트리**: GHC 9.8.x — 좀 더 보수적으로 가고 싶다면.

- **레거시**: GHC 9.6.x 미만은 2026년에 새로 시작할 이유가 없다.

3장 · GHCup — 권장 설치 도구

2020년쯤만 해도 Haskell 설치는 "Stack 깔고 끝"이었다. Cabal 사용자는 별도로 깔았고, 둘은 서로 미묘하게 안 맞았다.

2026년에는 **GHCup이 공식 권장 설치 도구**다. `haskell.org/ghcup`에서 한 줄 설치 스크립트를 실행하면, GHC·Cabal·Stack·HLS(Haskell Language Server)가 다 깔린다.

공식 설치 한 줄

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

또는 Windows PowerShell

Set-ExecutionPolicy Bypass -Scope Process -Force

Invoke-WebRequest ... ghcup-windows-... .ps1 | Invoke-Expression

설치 후 `ghcup tui`를 실행하면 텍스트 기반 UI가 뜨고, 거기서 원하는 GHC·Cabal·Stack·HLS 버전을 골라 설치/제거할 수 있다.

ghcup install ghc 9.10.1

ghcup install ghc 9.12.1

ghcup set ghc 9.10.1 # 시스템 기본 GHC를 9.10으로

ghcup install cabal 3.14.1.0

ghcup install hls 2.9.0.0 # Haskell Language Server (LSP)

ghcup install stack 3.1.1

ghcup list # 설치된 / 설치 가능한 버전 보기

GHCup의 핵심 가치는 **하나의 호스트에 GHC를 여러 버전 공존시킬 수 있다는 점**이다. 프로젝트마다 `cabal.project`나 `stack.yaml`에 지정된 GHC를 자동으로 골라 쓴다.

> 참고: macOS·Linux는 위 스크립트가 표준이고, Windows는 GHCup가 chocolatey를 통하지 않고 자체 설치한다. WSL 사용자도 동일 스크립트를 쓰면 된다.

4장 · Cabal 3.14 / Stack — 빌드 도구

GHC가 컴파일러라면, Cabal·Stack은 그 위의 패키지·프로젝트 관리자다.

Cabal 3.14

Cabal은 두 가지다.

1. **Cabal 라이브러리** — `*.cabal` 파일 포맷을 읽고 빌드 그래프를 만드는 코어.

2. **cabal-install CLI** — 그 라이브러리를 쓰는 명령행 도구. 보통 우리가 "cabal"이라고 부를 때는 이쪽.

Cabal 3.14는 2024년 말 릴리스로, 다음이 개선되었다.

- **`cabal repl`** 멀티 컴포넌트 지원 — 라이브러리·실행파일·테스트 스위트를 한 REPL에서.

- **`cabal-install`의 의존성 해결기** 속도 향상 — 큰 의존성 트리에서 체감.

- **`cabal.project.local`** 우선순위 명확화.

- **재현 가능한 빌드** — `index-state` 핀이 더 안정적으로 동작.

-- my-app.cabal (Cabal 3.14)

cabal-version: 3.14

name: my-app

version: 0.1.0.0

synopsis: A sample modern Haskell app

license: BSD-3-Clause

build-type: Simple

common warnings

ghc-options: -Wall -Wcompat -Widentities -Wincomplete-uni-patterns

library

import: warnings

exposed-modules: MyApp

MyApp.Server

build-depends: base ^>= 4.20

, servant ^>= 0.20

, servant-server ^>= 0.20

, warp ^>= 3.4

, aeson ^>= 2.2

, text ^>= 2.1

hs-source-dirs: src

default-language: GHC2024

executable my-app

import: warnings

main-is: Main.hs

build-depends: base, my-app

hs-source-dirs: app

default-language: GHC2024

test-suite my-app-test

import: warnings

type: exitcode-stdio-1.0

main-is: Spec.hs

build-depends: base, my-app, hspec ^>= 2.11, tasty ^>= 1.5

hs-source-dirs: test

default-language: GHC2024

Stack

Stack은 FP Complete가 만들었고 지금은 Haskell Foundation 산하 커뮤니티가 유지한다. Cabal과 다른 점은 **Stackage라는 큐레이션된 LTS 스냅샷을 기본으로 쓴다**는 것.

stack.yaml

resolver: lts-22.30 # Stackage LTS — 같이 빌드되는 패키지들이 검증된 묶음

packages:

- .

extra-deps: []

Stackage LTS는 매주 새 마이너 릴리스가, 6개월마다 새 메이저가 나온다. "이 패키지 묶음은 같이 빌드되고 같이 테스트가 통과한다"가 보장이다.

어느 도구를 쓸까

- **새 프로젝트, 빠르게**: Stack (Stackage LTS) — 의존성 충돌 걱정이 적다.

- **라이브러리·메인스트림 OSS**: Cabal — Hackage 직접 배포가 자연스럽다.

- **둘 다 지원**: 대부분의 큰 프로젝트는 `cabal.project`와 `stack.yaml` 둘 다 둔다.

2026년에는 Cabal 진영이 더 빠르게 발전했지만, Stack의 "잡음 적은" UX는 여전히 매력적이다.

5장 · Hackage / Stackage — 패키지 생태계

Hackage

`hackage.haskell.org` — Haskell의 중앙 패키지 저장소. 2026년 기준 약 18,000개 패키지. 누구나 올릴 수 있고, 버전 핀은 SemVer 비슷한 PVP(Package Versioning Policy)를 따른다.

cabal update # Hackage 인덱스 새로고침

cabal install --installdir=./bin pandoc

cabal info aeson # 패키지 정보

Stackage

`stackage.org` — Hackage 위에 큐레이션 레이어를 얹은 것. LTS(장기 지원)와 Nightly로 나뉜다.

- **LTS-22.x** (2024년 말 시작) — GHC 9.8/9.10 기반 묶음

- **LTS-23.x** (2025년 중반) — GHC 9.10/9.12 기반

- **Nightly** — 매일 새로 빌드, 가장 최신 패키지 묶음

Stackage가 중요한 이유: "X 패키지를 쓰면 Y와 의존성 충돌이 난다"가 큐레이션 단계에서 걸러진다. 라이브러리 저자가 `stack.yaml`에 `resolver: lts-22.30`만 적으면, 그 묶음 안의 모든 패키지가 같이 빌드된다.

6장 · IHP (Integrated Haskell Platform) — 풀스택 웹

`ihp.digitallyinduced.com` — 독일의 digitally induced GmbH가 만든 풀스택 웹 프레임워크. **Rails / Phoenix / Laravel 같은 경험을 Haskell에서 제공**하는 것이 목표.

IHP의 철학

- **convention over configuration** — 디렉터리 구조와 명명 규약을 따르면 코드량이 줄어든다.

- **type-safe** — 라우터, 폼, DB 쿼리, 뷰가 전부 타입으로 묶인다.

- **dev tooling** — 개발 서버, 마이그레이션 GUI(IHP IDE라 부른다), 코드 생성기.

새 IHP 프로젝트

nix-shell -p ihp-new --run "ihp-new my-blog"

cd my-blog

./start # http://localhost:8000

IHP 모델 예시

-- Application/Schema.sql (SQL로 직접 정의)

CREATE TABLE posts (

id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,

title TEXT NOT NULL,

body TEXT NOT NULL,

created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL

);

-- Web/Controller/Posts.hs (생성된 컨트롤러를 손본 것)

module Web.Controller.Posts where

instance Controller PostsController where

action PostsAction = do

posts <- query @Post |> fetch

render IndexView { .. }

-- Web/View/Posts/Index.hs

module Web.View.Posts.Index where

data IndexView = IndexView { posts :: [Post] }

instance View IndexView where

html IndexView { .. } = [hsx|

{forEach posts renderPost}

|]

where

renderPost post = [hsx|<li>{get #title post}</li>|]

`hsx` 따옴 안에서는 IHP 전용 quasi-quoter가 동작하기 때문에, 중괄호 보간이 Haskell 값으로 안전하게 해석된다. (이건 IHP의 DSL 안에서만 그렇고, 일반 Haskell 파일과는 다르다.)

IHP가 잘 어울리는 경우

- **혼자 만드는 사이드 프로젝트** — Rails처럼 빠르게 CRUD를 굴리고 싶을 때.

- **소규모 팀의 SaaS 백오피스** — 마이그레이션·인증·관리 화면이 기본 제공.

- **Haskell 초보자 진입로** — 모나드 변환자 같은 개념을 정면으로 부딪치지 않고 "어쨌든 동작하는 웹앱"을 만들 수 있다.

7장 · Servant — 타입드 HTTP API

IHP가 풀스택이라면, Servant는 **API 전용 라이브러리**다. 핵심 아이디어 하나: **API를 타입 레벨로 표현한다**.

{-# LANGUAGE DataKinds #-}

{-# LANGUAGE TypeOperators #-}

module Api where

data User = User

{ userId :: Int

, userName :: String

} deriving (Generic)

instance ToJSON User

instance FromJSON User

-- API를 타입으로

type UserAPI =

"users" :> Get '[JSON] [User]

:<|> "users" :> Capture "id" Int :> Get '[JSON] User

:<|> "users" :> ReqBody '[JSON] User :> Post '[JSON] User

-- 그 타입의 핸들러

userAPI :: Server UserAPI

userAPI = listUsers :<|> getUser :<|> createUser

where

listUsers = pure [User 1 "alice", User 2 "bob"]

getUser uid = pure (User uid "alice")

createUser u = pure u

이 코드의 마법은 `UserAPI`라는 **타입**이 진실의 원천이라는 것이다.

- 핸들러를 잘못 짜면 **컴파일이 안 된다**. 예를 들어 `Get '[JSON] [User]`로 선언된 라우트가 `Int`를 돌려주면 GHC가 거부한다.

- 클라이언트 — `servant-client` — 도 같은 타입에서 자동 생성된다.

- OpenAPI/Swagger 문서 — `servant-openapi3` — 도 같은 타입에서 자동 생성된다.

Servant + warp로 서버 띄우기

main :: IO ()

main = do

putStrLn "Listening on http://localhost:8081"

run 8081 (serve (Proxy :: Proxy UserAPI) userAPI)

누가 Servant를 쓰는가

- **Hasura GraphQL Engine** 일부 내부 서비스

- **Channable**, **Mercury Bank**, **Wire**

- 수많은 OSS 백엔드

API 변경이 곧 컴파일러 에러가 되는 안전망이 핵심이다.

8장 · Yesod / Snap / Scotty / Spock — 그 외 웹

Yesod (Michael Snoyman)

`yesodweb.com` — Stack/Stackage의 만든이이기도 한 Michael Snoyman이 만든 풀스택 프레임워크. IHP보다 일찍 시작했고, **Type-safe URL**과 **Type-safe widget** 같은 무거운 타입 사용으로 유명하다.

-- Foundation.hs (Yesod 라우팅 스니펫)

mkYesodData "App" [parseRoutes|

/ HomeR GET

/posts PostsR GET POST

/posts/#PostId PostR GET DELETE

|]

Snap

`snapframework.com` — 학술적 뿌리가 강한 프레임워크. **Snaplets**라는 모듈 시스템이 특징. 활발한 신규 개발은 줄었지만 기존 프로젝트에서 쓰인다.

Scotty

`hackage.haskell.org/package/scotty` — **Sinatra 스타일의 마이크로 프레임워크**. 짧고 가벼운 API를 빠르게 띄우는 데 좋다.

{-# LANGUAGE OverloadedStrings #-}

main :: IO ()

main = scotty 3000 $ do

get "/" $ text "hello scotty"

get "/hello/:name" $ do

n <- captureParam "name"

text ("hello, " <> n)

Spock

Scotty와 비슷한 마이크로 프레임워크지만 세션·CSRF·DB 풀 같은 미들웨어가 기본 제공된다.

어느 걸 쓰지

- **타입드 API 중심**: Servant.

- **풀스택 / DB 마이그레이션까지 한 번에**: IHP.

- **풀스택 / 깊은 타입 사용**: Yesod.

- **마이크로 서비스 / 사이드카**: Scotty.

- **세션·인증 포함 마이크로**: Spock.

9장 · 효과 시스템 — Effectful (mtl 대체) / Polysemy / fused-effects / Bluefin

Haskell의 매력이자 진입장벽이 효과(effects) 시스템이다. 부수 효과 — IO, 상태, 예외, 로깅, DB 접근 — 를 타입으로 추적한다.

전통은 **mtl 스타일**이었다. 모나드 변환자(`StateT`, `ReaderT`, `ExceptT`)를 쌓아 올린다. 강력하지만 컴파일 메시지가 늘어지고 성능 트레이드오프가 있다.

2026년에는 **Effectful**이 사실상 mtl의 자리를 빼앗고 있다.

Effectful

`hackage.haskell.org/package/effectful` — Polysemy/fused-effects보다 단순한 모델, 컴파일러 친화적 성능, mtl과 거의 같은 사용감.

{-# LANGUAGE DataKinds #-}

{-# LANGUAGE TypeApplications #-}

{-# LANGUAGE GADTs #-}

-- 효과를 명시: Reader + Error

loadUser :: (Reader String :> es, Error String :> es) => Int -> Eff es String

loadUser uid = do

prefix <- ask

if uid > 0

then pure (prefix ++ ": user-" ++ show uid)

else throwError "invalid uid"

main :: IO ()

main = do

result <- runEff

. runError @String

. runReader "PREFIX"

$ loadUser 42

print result -- Right "PREFIX: user-42"

Polysemy

`hackage.haskell.org/package/polysemy` — "Free Monad + Free Algebra"의 학술적 정통. 강력한 인터프리터 변경 능력, 무거운 타입.

fused-effects

`hackage.haskell.org/package/fused-effects` — Carrier 기반 효과 시스템. 컴파일 시 효과 합성을 펼쳐서 성능을 끌어올린다.

Bluefin

`hackage.haskell.org/package/bluefin` — 2024-25년 등장한 새 효과 라이브러리. **scoped effects**와 **delimited continuations**를 1급으로. GHC 9.10의 새 RTS 기능을 활용한다.

-- Bluefin 스타일 (개념적 예시)

bumpCounter :: e :> es => State Int e -> Eff es Int

bumpCounter ref = do

modify ref (+ 1)

get ref

누가 어느 걸 써야 하나

- **새 코드, 익숙한 mtl 감각**: Effectful.

- **연구·교육·강한 표현력**: Polysemy.

- **성능에 민감, 정형 호출 그래프**: fused-effects.

- **새것 좋아함, scoped effects**: Bluefin.

10장 · ORM — Persistent / Beam / Esqueleto

Persistent (Yesod 진영)

Michael Snoyman의 `persistent` — 데이터 모델을 DSL로 적고, 컴파일러가 그걸 받아 데이터 타입과 마이그레이션을 만든다. SQL과 NoSQL 백엔드 둘 다 지원.

{-# LANGUAGE QuasiQuotes #-}

{-# LANGUAGE TemplateHaskell #-}

{-# LANGUAGE TypeFamilies #-}

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|

Post

title Text

body Text

deriving Show

User

name Text

posts [PostId]

deriving Show

|]

Beam

`haskell-beam.github.io` — Generic 기반의 더 타입 안전한 SQL. Persistent보다 SQL에 가까운 추상화, Postgres·MySQL·SQLite 백엔드.

Esqueleto

Persistent 위에 얹어 **타입 안전한 JOIN과 서브쿼리**를 표현하는 EDSL.

-- 사용자의 게시글 수

usersWithPostCount = E.select $ do

(u E.:& p) <- E.from $ E.table @User

`E.leftJoin` E.table @Post

`E.on` (\(u E.:& p) -> E.just (u E.^. UserId) E.==. p E.?. PostUserId)

E.groupBy (u E.^. UserId)

pure (u, E.count (p E.?. PostId))

어느 걸 쓰지

- **빠른 CRUD**: Persistent.

- **JOIN 많은 분석 쿼리**: Esqueleto + Persistent.

- **SQL 가까이, 큰 도메인**: Beam.

11장 · Megaparsec — 파서 콤비네이터

`hackage.haskell.org/package/megaparsec` — 2026년 표준 파서 콤비네이터 라이브러리. Parsec의 후계자, Attoparsec과 달리 **사람이 읽기 좋은 에러 메시지**가 핵심.

{-# LANGUAGE OverloadedStrings #-}

type Parser = Parsec Void Text

data JsonValue

= JNull

| JBool Bool

| JNumber Double

| JString Text

| JArray [JsonValue]

deriving Show

sc :: Parser ()

sc = L.space space1 (L.skipLineComment "//") empty

lexeme :: Parser a -> Parser a

lexeme = L.lexeme sc

jsonNull :: Parser JsonValue

jsonNull = JNull <$ lexeme (string "null")

jsonBool :: Parser JsonValue

jsonBool = JBool True <$ lexeme (string "true")

<|> JBool False <$ lexeme (string "false")

jsonNumber :: Parser JsonValue

jsonNumber = JNumber <$> lexeme L.signed L.float

jsonValue :: Parser JsonValue

jsonValue = choice [jsonNull, jsonBool, jsonNumber]

Megaparsec의 장점:

- **자동 위치 추적** — 에러가 어디서 났는지 줄·칸으로 표시.

- **사용자 정의 에러** — `customFailure`로 도메인 특화 에러 추가.

- **백트래킹 제어** — `try`로 명시적으로.

Pandoc도 내부에서 Megaparsec(과 그 전 세대인 Parsec)을 광범위하게 쓴다.

12장 · Aeson — JSON

`hackage.haskell.org/package/aeson` — Haskell의 사실상 표준 JSON 라이브러리. 2026년 2.2 메이저 라인이 안정.

{-# LANGUAGE DeriveGeneric #-}

{-# LANGUAGE OverloadedStrings #-}

data Post = Post

{ postId :: Int

, postTitle :: String

} deriving (Show, Generic)

instance ToJSON Post where

toEncoding = genericToEncoding defaultOptions

instance FromJSON Post

main :: IO ()

main = do

let p = Post 1 "Hello"

bs = encode p

print bs

print (decode bs :: Maybe Post)

Aeson 2 핵심

- **KeyMap** — 객체 키가 `Text`에서 `Key`로 바뀌면서 충돌·해시 보안 강화.

- **Generic 디폴트가 충분히 빠르다** — Template Haskell 매크로 안 써도 된다.

- **Custom Options** — `fieldLabelModifier`로 `snake_case` ↔ `camelCase` 변환 자연스럽게.

options :: Options

options = defaultOptions

{ fieldLabelModifier = camelTo2 '_' -- postId → post_id

, omitNothingFields = True

}

13장 · 테스트 — hedgehog / tasty / hspec

Haskell 테스트 생태계는 세 축이다.

hspec (BDD)

main :: IO ()

main = hspec $ do

describe "sum" $ do

it "sums an empty list to 0" $

sum ([] :: [Int]) `shouldBe` 0

it "sums [1,2,3] to 6" $

sum [1, 2, 3 :: Int] `shouldBe` 6

tasty (테스트 러너)

다양한 테스트 라이브러리를 하나의 트리에 묶어주는 러너. `tasty-hspec`, `tasty-hedgehog`, `tasty-hunit` 등의 어댑터.

main :: IO ()

main = defaultMain $ testGroup "all"

[ testCase "trivial" $ (1 + 1) @?= (2 :: Int)

]

hedgehog (property testing)

QuickCheck의 후계자. **integrated shrinking** — 실패 케이스가 자동으로 최소 반례까지 줄어든다.

prop_reverse_involutive :: Property

prop_reverse_involutive = property $ do

xs <- forAll $ Gen.list (Range.linear 0 100) (Gen.int Range.linearBounded)

reverse (reverse xs) === xs

property test가 강력한 이유: "케이스 5개"가 아니라 "수천 개의 임의 입력에서 불변식이 성립함"을 확인한다. 그리고 깨지면 hedgehog가 자동으로 줄여서 사람이 보기 좋은 반례를 준다.

누가 어느 걸

- **BDD 단위 테스트**: hspec.

- **러너 통합**: tasty.

- **속성·반례 자동 축소**: hedgehog.

14장 · Liquid Haskell — Refinement Types

`ucsd-progsys.github.io/liquidhaskell-blog/` — 일반 Haskell 위에 **refinement types**(부분 타입)를 얹는 정형 검증 도구.

핵심 아이디어: 타입 옆에 술어를 적으면, SMT 솔버(Z3 등)가 그 술어가 항상 성립함을 컴파일 시간에 증명한다.

{-@ measure llen @-}

llen :: [a] -> Int

llen [] = 0

llen (_:xs) = 1 + llen xs

{-@ head :: { xs:[a] | llen xs > 0 } -> a @-}

head :: [a] -> a

head (x:_) = x

head [] = error "won't happen" -- LH가 이 라인이 도달 불가임을 증명

LH는 "이 함수는 빈 리스트로 호출될 수 없다"는 사실을 **타입의 일부**로 적게 하고, 호출처에서 그 조건을 만족시키지 못하면 컴파일러가 거부한다.

학계와 일부 산업(블록체인, 항공·자동차 안전 쪽)에서 사용한다.

15장 · Hasktorch — 머신러닝

`hasktorch.org` — PyTorch의 libtorch 라이브러리를 Haskell에서 바인딩. Tweag·HaskellML이 적극 개발.

{-# LANGUAGE DataKinds #-}

main :: IO ()

main = do

x <- randn' [2, 3] -- Tensor [2, 3]

y <- randn' [3, 4]

let z = matmul x y

print z

Hasktorch가 매력적인 이유는 **타입으로 텐서 차원을 표현**할 수 있다는 점이다.

-- 컴파일 타임에 차원이 검증되는 행렬곱

matmul' :: Tensor '[2, 3] Float -> Tensor '[3, 4] Float -> Tensor '[2, 4] Float

matmul' = matmul

차원이 안 맞는 행렬을 곱하려고 하면 GHC가 거부한다. PyTorch 사용자에게는 익숙한 실수가 컴파일 타임에 잡힌다.

16장 · Pandoc — John MacFarlane

`pandoc.org` — UC Berkeley 철학과 교수 **John MacFarlane**이 2006년부터 메인테인 중인 **만능 문서 변환기**. 입력 포맷 약 40개, 출력 포맷 약 60개. Markdown · LaTeX · DOCX · HTML · ePub · PDF · MediaWiki · RST 같은 사이를 자유롭게 오간다.

마크다운 → PDF

pandoc README.md -o readme.pdf

마크다운 → DOCX, 참고문헌 자동

pandoc paper.md --citeproc --bibliography refs.bib -o paper.docx

HTML → EPUB

pandoc book.html -o book.epub --metadata title="My Book"

Pandoc의 내부 구조도 멋지다.

- **PandocAST** — 입력 포맷이 무엇이든 이 AST로 정규화.

- **Reader** — 입력 포맷별 파서 (Markdown reader, LaTeX reader, ...).

- **Writer** — 출력 포맷별 시리얼라이저 (HTML writer, PDF writer via LaTeX, ...).

- **Filter** — Lua 또는 Haskell로 AST를 변환.

Haskell 생태계에서 가장 가시적인 "최종 사용자가 매일 쓰는" 프로젝트다.

17장 · Cardano — Charles Hoskinson IOHK

`cardano.org` — Ethereum 공동창립자 **Charles Hoskinson**이 떠나서 만든 블록체인 플랫폼. 개발사 **IOG**(Input Output Global, 옛 IOHK)가 운영. 노드는 **전부 Haskell**, 스마트 컨트랙트는 **Plutus**(Haskell DSL)로 짠다.

왜 Haskell이었나:

- **정형 검증** — 금융을 다루기 때문에 "이 코드가 정해진 명세를 만족함"을 수학적으로 보여야 했다.

- **순수성** — 합의 알고리듬은 결정적이어야 한다. IO를 격리한 Haskell이 자연스럽다.

- **타입 시스템** — 검증된 변경을 보장.

Cardano 코어는 다음으로 구성된다.

- `cardano-node` — 노드 데몬, Haskell.

- `cardano-ledger` — 원장 규칙, Haskell 명세에서 직접 구현.

- `plutus-core` — 스마트 컨트랙트 코어 언어.

- **Plutus Tx** — Plutus로 컴파일되는 Haskell 부분 집합.

-- Plutus Tx (개념적 예시)

{-# INLINABLE mkValidator #-}

mkValidator :: () -> Integer -> ScriptContext -> Bool

mkValidator _ guess _ = guess == 42

이게 온체인에 올라가서 트랜잭션을 검증한다. Plutus는 Haskell 부분집합을 Plutus Core라는 자체 코어 언어로 컴파일하고, 그 코어 언어를 노드가 평가한다.

18장 · 한국 / 일본 — 한국어 Haskell, ja-haskell, IOHK Japan

한국

- **Haskell Korea (페이스북 그룹·디스코드)** — 2010년대 중반부터 유지된 커뮤니티. 분기마다 비정기 모임.

- 출판물: 김정민·이형주 외의 번역서(예: "Haskell Programming from First Principles" 등 일부), 그리고 국내 저자가 쓴 "Programming Haskell"류 책.

- 대학: KAIST·서울대·POSTECH의 PL 그룹이 Haskell을 교육·연구에 쓴다.

- 산업 사용은 제한적이지만 핀테크·시큐리티 일부 팀이 도입.

일본

- **ja-haskell** — 일본어 Haskell 커뮤니티 슬랙·X. 매주 활발.

- **Haskell Day**, **Haskell Symposium Japan**(부정기) — 발표 중심 이벤트.

- 책: 山本和彦(Kazu Yamamoto, IIJ Lab)의 "プログラミングHaskell" 번역, 그 외 다수.

- **IOHK Japan** — Cardano IOG의 일본 지사가 도쿄에 있고, Haskell 채용이 가장 활발한 곳 중 하나.

- 산업: **Tsuru Capital**, **HERP**, **Drivemode(Honda 인수)** 등이 Haskell 사용.

영어 커뮤니티(`r/haskell`, Haskell Discourse, Discord) 외에 두 지역 커뮤니티의 자료를 같이 보면 진입이 부드럽다.

19장 · 누가 Haskell을 배워야 하나

Haskell을 추천하는 두 가지 경우다.

1. 함수형 프로그래밍을 정면으로 배우고 싶을 때

JavaScript·Kotlin·Scala·OCaml에서 함수형 스타일을 쓰는 것과, **순수성과 게으름**이 디폴트인 환경에서 쓰는 것은 다르다. Haskell은 도망갈 곳이 없다. 모든 부수효과가 타입에 드러난다. 이게 배우는 입장에서는 처음엔 답답하지만, 한 번 익숙해지면 **다른 언어를 짤 때도 머릿속 모델이 달라진다**.

2. 검증·DSL이 가치가 큰 도메인

- 금융(파생상품 가격 계산, 정산)

- 블록체인 스마트 컨트랙트

- 컴파일러·언어 도구 (Pandoc, ShellCheck, Idris, dhall 같은 도구들이 다 Haskell)

- 정형 검증이 필요한 항공·자동차·의료 일부

- 복잡한 도메인 규칙이 있는 보험·세무

Haskell이 안 어울리는 경우

- 팀이 큰데 Haskell을 아는 사람이 본인뿐 — 채용·온보딩 비용이 크다.

- 매우 짧은 MVP, 라이브러리가 부족한 도메인.

- 시스템 프로그래밍 / 임베디드 — Rust가 더 자연스럽다.

20장 · 참고 / References

- GHC 9.10 release notes — `downloads.haskell.org/ghc/9.10.1/docs/users_guide/9.10.1-notes.html`

- GHC 9.12 release notes — `downloads.haskell.org/ghc/9.12.1/docs/users_guide/9.12.1-notes.html`

- GHCup — `www.haskell.org/ghcup/`

- Cabal — `cabal.readthedocs.io`

- Stack — `docs.haskellstack.org`

- Stackage — `www.stackage.org`

- Hackage — `hackage.haskell.org`

- IHP — `ihp.digitallyinduced.com`

- Servant — `docs.servant.dev`

- Yesod — `www.yesodweb.com`

- Snap — `snapframework.com`

- Scotty — `hackage.haskell.org/package/scotty`

- Effectful — `hackage.haskell.org/package/effectful`

- Polysemy — `hackage.haskell.org/package/polysemy`

- fused-effects — `hackage.haskell.org/package/fused-effects`

- Bluefin — `hackage.haskell.org/package/bluefin`

- Persistent — `hackage.haskell.org/package/persistent`

- Beam — `haskell-beam.github.io`

- Esqueleto — `hackage.haskell.org/package/esqueleto`

- Megaparsec — `hackage.haskell.org/package/megaparsec`

- Aeson — `hackage.haskell.org/package/aeson`

- hedgehog — `hedgehog.qa`

- tasty — `hackage.haskell.org/package/tasty`

- hspec — `hspec.github.io`

- Liquid Haskell — `ucsd-progsys.github.io/liquidhaskell-blog/`

- Hasktorch — `hasktorch.org`

- Pandoc — `pandoc.org`

- Cardano — `cardano.org`

- IOG — `iohk.io`

- Haskell Foundation — `haskell.foundation`

- Haskell Korea — Facebook group / Discord

- ja-haskell — `haskell.jp`

현재 단락 (1/459)

매년 누군가는 묻는다. "Haskell, 아직도 써요?"

작성 글자: 0원문 글자: 17,663작성 단락: 0/459