Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

22장: 실용 프로그래밍 (Practical Programming)

FunLang는 일상적인 프로그래밍을 더 편리하게 만드는 세 가지 기능을 제공합니다. 뉴라인 암묵적 시퀀싱, 컬렉션 for-in 루프, 그리고 Option/Result 유틸리티 함수입니다. 이 장에서는 각 기능을 코드 예제와 함께 살펴봅니다.

뉴라인 암묵적 시퀀싱 (Newline Implicit Sequencing)

; 연산자로 표현식을 순서대로 실행할 수 있지만, 들여쓰기 블록 안에서는 줄 바꿈만으로도 동일한 효과를 낼 수 있습니다. 같은 들여쓰기 수준의 줄은 자동으로 ;으로 연결됩니다.

함수 본체에서의 뉴라인 시퀀싱

함수 본체에서 여러 줄에 걸쳐 표현식을 나열하면, 각 줄이 순서대로 실행됩니다. 마지막 표현식의 값이 함수의 반환값이 됩니다.

$ cat greet.l3
let greet name =
    println ("Hello, " ^^ name)
    println "Welcome to FunLang"
let _ = greet "Alice"

$ fn greet.l3
Hello, Alice
Welcome to FunLang
()

greet 함수는 println ("Hello, " ^^ name)println "Welcome to FunLang" 두 표현식을 순서대로 실행합니다. println의 반환값은 unit이므로, 마지막 println의 unit이 함수의 반환값이 됩니다.

if/else 본체에서의 뉴라인 시퀀싱

if/else의 then 브랜치와 else 브랜치도 들여쓰기 블록으로 여러 줄을 쓸 수 있습니다.

$ cat check.l3
let check x =
    if x > 0 then
        println "positive"
        x * 2
    else
        println "non-positive"
        0
let result = check 5

$ fn check.l3
positive
10

check 5를 실행하면 then 브랜치에서 println "positive"를 실행한 뒤 5 * 2 = 10을 반환합니다. 최상위 let result = check 5는 반환값 10을 출력합니다.

들여쓰기 수준에 주의하세요. then 브랜치의 표현식은 then 키워드보다 더 깊게 들여써야 하고, else 브랜치의 표현식은 else 키워드보다 더 깊게 들여써야 합니다.

컬렉션 for-in 루프 (For-In Collection Loops)

컬렉션의 원소를 순서대로 순회하는 for x in collection do 문법을 제공합니다. 리스트, 배열은 물론 Hashtable, HashSet, Queue, MutableList 등 모든 가변 컬렉션도 지원합니다. 인덱스가 필요 없을 때 for i = 0 to n do arr.[i]보다 훨씬 간결하게 컬렉션을 처리할 수 있습니다.

리스트 순회

$ cat list_iter.l3
let nums = [1; 2; 3]
let _ =
    for n in nums do
        println (to_string n)

$ fn list_iter.l3
1
2
3
()

for n in nums do 문법으로 리스트 nums의 각 원소를 n에 바인딩하며 순회합니다. 루프 변수 n은 불변이며, 루프 전체의 반환값은 unit입니다. 따라서 let _ =로 감싸서 최상위에서 실행합니다.

배열 순회

$ cat arr_iter.l3
let arr = array_create 3 0
let _ = arr.[0] <- 10
let _ = arr.[1] <- 20
let _ = arr.[2] <- 30
let _ =
    for x in arr do
        println (to_string x)

$ fn arr_iter.l3
10
20
30
()

배열도 동일한 문법으로 순회합니다. 원소는 인덱스 순서(0, 1, 2, …)로 처리됩니다.

Hashtable 순회와 패턴 분해

Hashtable을 for-in으로 순회할 때 튜플 패턴으로 키와 값을 동시에 바인딩할 수 있습니다:

$ cat ht_forin.l3
let ht = Hashtable.create ()
let _ = Hashtable.set ht "name" "Alice"
let _ = for (k, v) in ht do
  let _ = println k
  println v

$ fn ht_forin.l3
name
Alice
()

HashSet, Queue, MutableList도 동일한 for x in coll do 구문으로 순회할 수 있습니다.

루프 변수의 불변성

for-in 루프 변수는 for 범위 루프와 마찬가지로 불변입니다. 루프 본체 안에서 대입을 시도하면 E0320 에러가 발생합니다. 루프 안에서 집계가 필요하다면 외부에 let mut 변수를 선언하세요.

Option/Result 유틸리티 (Option/Result Utilities)

Prelude는 Option 타입과 Result 타입을 다루는 유틸리티 함수를 제공합니다. 패턴 매칭 없이 간결하게 Option/Result 값을 변환하고 조합할 수 있습니다.

optionMap과 optionBind

optionMap f optoptSome x이면 Some (f x)를, None이면 None을 반환합니다. optionBind f optoptSome x이면 f x(Option 반환)를, None이면 None을 반환합니다.

$ cat option_map_bind.l3
let doubled = optionMap (fun x -> x * 2) (Some 21)
let chained = optionBind (fun x -> if x > 10 then Some (x + 1) else None) doubled
let _ = println (to_string doubled)
let _ = println (to_string chained)

$ fn option_map_bind.l3
Some 42
Some 43
()

optionMap (fun x -> x * 2) (Some 21)Some 42를 반환합니다. optionBindSome 42에서 42를 꺼내 if 42 > 10 then Some 43을 반환합니다.

optionDefaultValue와 optionFilter

optionDefaultValue default optoptNone일 때 default를 반환합니다. optionFilter pred opt는 술어(predicate)를 만족하지 않으면 None으로 바꿉니다.

$ cat option_default_filter.l3
let safe = optionDefaultValue 0 (Some 42)
let fallback = optionDefaultValue 0 None
let filtered = optionFilter (fun x -> x > 5) (Some 10)
let rejected = optionFilter (fun x -> x > 5) (Some 3)
let _ = println (to_string safe)
let _ = println (to_string fallback)
let _ = println (to_string filtered)
let _ = println (to_string rejected)

$ fn option_default_filter.l3
42
0
Some 10
None
()

optionDefaultValue 0 (Some 42)Some이므로 안의 값 42를 반환합니다. optionDefaultValue 0 None은 기본값 0을 반환합니다. optionFilter (fun x -> x > 5) (Some 3)은 술어를 만족하지 않으므로 None을 반환합니다.

resultMap과 resultToOption

resultMap f rOk x이면 Ok (f x)를, Error e이면 Error e를 반환합니다. resultToOption rOk x이면 Some x를, Error _이면 None을 반환합니다.

$ cat result_map_opt.l3
let r = Ok 42
let mapped = resultMap (fun x -> x * 2) r
let asOption = resultToOption mapped
let errCase = resultToOption (Error "oops")
let _ = println (to_string mapped)
let _ = println (to_string asOption)
let _ = println (to_string errCase)

$ fn result_map_opt.l3
Ok 84
Some 84
None
()

resultMap으로 Ok 값을 변환하고, resultToOption으로 Result를 Option으로 변환합니다. Error 케이스는 None으로 변환되어 에러 메시지가 사라집니다.

Option/Result 유틸리티 함수 요약

함수시그니처설명
optionMap(a -> b) -> Option a -> Option bSome이면 함수 적용, None 전파
optionBind(a -> Option b) -> Option a -> Option bOption 반환 함수로 체이닝
optionFilter(a -> bool) -> Option a -> Option a술어 불만족 시 None으로 변환
optionDefaultValuea -> Option a -> aNone일 때 기본값 반환
optionIsSomeOption a -> boolSome이면 true
optionIsNoneOption a -> boolNone이면 true
optionIter(a -> unit) -> Option a -> unitSome이면 부수 효과 실행
resultMap(a -> b) -> Result a e -> Result b eOk이면 함수 적용, Error 전파
resultToOptionResult a e -> Option aOk → Some, Error → None
resultDefaultValuea -> Result a e -> aError일 때 기본값 반환
resultIter(a -> unit) -> Result a e -> unitOk이면 부수 효과 실행

종합 예제 (Composition Example)

세 가지 기능을 조합한 예제입니다. Option 값의 리스트를 for-in으로 순회하면서 각 값에 함수를 적용합니다.

$ cat process.l3
let process items =
    let _ =
        for item in items do
            let result = optionMap (fun x -> x * 2) item
            println (to_string result)
    ()
let _ = process [Some 1; None; Some 3]

$ fn process.l3
Some 2
None
Some 6
()

process 함수는 Option 값의 리스트를 받아 각 원소에 optionMap (fun x -> x * 2)를 적용합니다. Some 1Some 2가 되고, NoneNone으로 유지되며, Some 3Some 6이 됩니다.

함수 본체에서 뉴라인 시퀀싱(for 루프와 let result = ...println ...)과 for-in 루프, optionMap을 자연스럽게 조합합니다.

구문 및 함수 요약

기능예시설명
뉴라인 시퀀싱들여쓰기 블록 내 줄 바꿈암묵적 ; 삽입
for x in list dofor n in nums do println (to_string n)리스트 원소 순회
for x in arr dofor x in arr do println (to_string x)배열 원소 순회
for (k, v) in ht dofor (k, v) in ht do println kHashtable 키-값 순회
for x in coll dofor x in hs do println (to_string x)HashSet/Queue/MutableList 순회
optionMap f optoptionMap (fun x -> x * 2) (Some 21)Option 변환
optionBind f optoptionBind f (Some x)Option 체이닝
optionDefaultValue d optoptionDefaultValue 0 None기본값 추출
optionFilter pred optoptionFilter (fun x -> x > 0) opt조건부 필터
resultMap f rresultMap (fun x -> x * 2) (Ok 42)Result 변환
resultToOption rresultToOption (Ok 42)Result → Option 변환