자유 모나드(Free Monad)는 임의의 함자(Functor)로부터 자동으로 모나드를 생성하는 구조다. DSL(도메인 특화 언어) 작성과 해석을 분리하는 데 강력하다.
정의
haskell
data Free f a
= Pure a
| Free (f (Free f a))
instance Functor f => Functor (Free f) where
fmap f (Pure a) = Pure (f a)
fmap f (Free fa) = Free (fmap (fmap f) fa)
instance Functor f => Monad (Free f) where
return = Pure
Pure a >>= f = f a
Free fa >>= f = Free (fmap (>>= f) fa)
DSL 작성 예시
haskell
-- 파일 시스템 DSL 정의
data FileSystemF next
= ReadFile FilePath (String -> next)
| WriteFile FilePath String next
| DeleteFile FilePath next
type FileSystem = Free FileSystemF
-- 스마트 생성자
readFile' :: FilePath -> FileSystem String
readFile' path = Free (ReadFile path Pure)
writeFile' :: FilePath -> String -> FileSystem ()
writeFile' path content = Free (WriteFile path content (Pure ()))
-- 프로그램 작성 (인터프리터와 독립)
copyFile :: FilePath -> FilePath -> FileSystem ()
copyFile src dst = do
content <- readFile' src
writeFile' dst content
-- 실제 IO 인터프리터
ioInterpreter :: FileSystem a -> IO a
ioInterpreter (Pure a) = return a
ioInterpreter (Free (ReadFile path next)) = do
content <- Prelude.readFile path
ioInterpreter (next content)
ioInterpreter (Free (WriteFile path content next)) = do
Prelude.writeFile path content
ioInterpreter next
-- 테스트 인터프리터 (순수)
testInterpreter :: Map FilePath String -> FileSystem a -> (a, Map FilePath String)
-- ... 파일 시스템을 Map으로 시뮬레이션
Free Monad vs Tagless Final
| 비교 | Free Monad | Tagless Final |
|---|
| 구조 | AST 생성 후 해석 | 직접 인코딩 |
| 확장성 | 인터프리터 추가 용이 | 연산 추가 용이 |
| 성능 | AST 오버헤드 | 직접 해석, 빠름 |
| 최적화 | AST 변환 가능 | 어려움 |
관련 개념