Functional Programming in Lean

4.6.Β Additional ConveniencesπŸ”—

4.6.1.Β Shared Argument TypesπŸ”—

같은 νƒ€μž…μ„ κ°–λŠ” μ—¬λŸ¬ 인수λ₯Ό λ°›λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•ŒλŠ” 같은 콜둠 μ•žμ— 인수λ₯Ό ν•¨κ»˜ μ“Έ 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ λ‹€μŒκ³Ό κ°™λ‹€.

def equal? [BEq Ξ±] (x : Ξ±) (y : Ξ±) : Option Ξ± := if x == y then some x else none

λ‹€μŒμ²˜λŸΌ μ“Έ μˆ˜λ„ μžˆλ‹€.

def equal? [BEq Ξ±] (x y : Ξ±) : Option Ξ± := if x == y then some x else none

μ΄λŠ” νƒ€μž… μ„œλͺ…이 클 λ•Œ 특히 μœ μš©ν•˜λ‹€.

4.6.2.Β Leading Dot NotationπŸ”—

κ·€λ‚© νƒ€μž…μ˜ μƒμ„±μžλŠ” λ„€μž„μŠ€νŽ˜μ΄μŠ€ μ•ˆμ— μžˆλ‹€. 이 덕뢄에 μ„œλ‘œ κ΄€λ ¨λœ μ—¬λŸ¬ κ·€λ‚© νƒ€μž…μ΄ 같은 μƒμ„±μž 이름을 μ‚¬μš©ν•  수 μžˆμ§€λ§Œ, ν”„λ‘œκ·Έλž¨μ΄ μž₯ν™©ν•΄μ§ˆ 수 μžˆλ‹€. ν•΄λ‹Ή κ·€λ‚© νƒ€μž…μ„ μ•Œκ³  μžˆλŠ” λ¬Έλ§₯μ—μ„œλŠ” μƒμ„±μž 이름 μ•žμ— 점을 λΆ™μ—¬ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μƒλž΅ν•  수 있으며, Lean은 μ˜ˆμƒ νƒ€μž…μ„ μ‚¬μš©ν•΄ μƒμ„±μž 이름을 κ²°μ •ν•œλ‹€. 예λ₯Ό λ“€μ–΄ 이진 트리λ₯Ό λŒ€μΉ­μ‹œν‚€λŠ” ν•¨μˆ˜λŠ” λ‹€μŒμ²˜λŸΌ μ“Έ 수 μžˆλ‹€.

def BinTree.mirror : BinTree Ξ± β†’ BinTree Ξ± | BinTree.leaf => BinTree.leaf | BinTree.branch l x r => BinTree.branch (mirror r) x (mirror l)

λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μƒλž΅ν•˜λ©΄ 훨씬 μ§§μ•„μ§€μ§€λ§Œ, Lean 컴파일러λ₯Ό ν¬ν•¨ν•˜μ§€ μ•ŠλŠ” μ½”λ“œ 리뷰 도ꡬ 같은 λ¬Έλ§₯μ—μ„œλŠ” ν”„λ‘œκ·Έλž¨μ„ 읽기 μ–΄λ €μ›Œμ§„λ‹€λŠ” λŒ€κ°€κ°€ λ”°λ₯Έλ‹€.

def BinTree.mirror : BinTree Ξ± β†’ BinTree Ξ± | .leaf => .leaf | .branch l x r => .branch (mirror r) x (mirror l)

μ‹μ˜ μ˜ˆμƒ νƒ€μž…μœΌλ‘œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό κ΅¬λΆ„ν•˜λŠ” 방법은 μƒμ„±μžκ°€ μ•„λ‹Œ 이름에도 μ μš©ν•  수 μžˆλ‹€. BinTree.emptyλ₯Ό BinTreeλ₯Ό λ§Œλ“œλŠ” λ‹€λ₯Έ λ°©λ²•μœΌλ‘œ μ •μ˜ν•˜λ©΄ 점 ν‘œκΈ°λ²•μœΌλ‘œλ„ μ‚¬μš©ν•  수 μžˆλ‹€.

def BinTree.empty : BinTree Ξ± := .leafBinTree.empty : BinTree Nat#check (.empty : BinTree Nat)
BinTree.empty : BinTree Nat

4.6.3.Β Or-PatternsπŸ”—

match μ‹μ²˜λŸΌ μ—¬λŸ¬ νŒ¨ν„΄μ„ ν—ˆμš©ν•˜λŠ” λ¬Έλ§₯μ—μ„œλŠ” μ—¬λŸ¬ νŒ¨ν„΄μ΄ κ²°κ³Ό 식을 κ³΅μœ ν•  수 μžˆλ‹€. μš”μΌμ„ λ‚˜νƒ€λ‚΄λŠ” 데이터 νƒ€μž… Weekdayλ₯Ό 보자.

inductive Weekday where | monday | tuesday | wednesday | thursday | friday | saturday | sunday deriving Repr

νŒ¨ν„΄ 맀칭을 μ‚¬μš©ν•΄ μ–΄λ–€ 날이 주말인지 검사할 수 μžˆλ‹€.

def Weekday.isWeekend (day : Weekday) : Bool := match day with | Weekday.saturday => true | Weekday.sunday => true | _ => false

μƒμ„±μž 점 ν‘œκΈ°λ²•μ„ μ‚¬μš©ν•˜λ©΄ 이λ₯Ό 이미 κ°„μ†Œν™”ν•  수 μžˆλ‹€.

def Weekday.isWeekend (day : Weekday) : Bool := match day with | .saturday => true | .sunday => true | _ => false

두 주말 νŒ¨ν„΄μ˜ κ²°κ³Ό 식이 λͺ¨λ‘ (true)둜 κ°™μœΌλ―€λ‘œ ν•˜λ‚˜λ‘œ ν•©μΉ  수 μžˆλ‹€.

def Weekday.isWeekend (day : Weekday) : Bool := match day with | .saturday | .sunday => true | _ => false

μΈμˆ˜μ— 이름을 뢙이지 μ•ŠλŠ” λ²„μ „μœΌλ‘œ 더 κ°„μ†Œν™”ν•  μˆ˜λ„ μžˆλ‹€.

def Weekday.isWeekend : Weekday β†’ Bool | .saturday | .sunday => true | _ => false

λ‚΄λΆ€μ μœΌλ‘œλŠ” 각 νŒ¨ν„΄μ— κ²°κ³Ό 식을 λ‹¨μˆœνžˆ λ³΅μ œν•œλ‹€. λ”°λΌμ„œ νŒ¨ν„΄μ΄ λ³€μˆ˜λ₯Ό 바인딩할 수 μžˆλ‹€. λ‹€μŒ μ˜ˆμ œμ—μ„œλŠ” 두 μƒμ„±μžκ°€ 같은 νƒ€μž…μ˜ 값을 λ‹΄λŠ” ν•© νƒ€μž…μ—μ„œ inlκ³Ό inr μƒμ„±μžλ₯Ό μ œκ±°ν•œλ‹€.

def condense : Ξ± βŠ• Ξ± β†’ Ξ± | .inl x | .inr x => x

κ²°κ³Ό 식을 λ³΅μ œν•˜λ―€λ‘œ νŒ¨ν„΄μ΄ λ°”μΈλ”©ν•˜λŠ” λ³€μˆ˜λ“€μ΄ 같은 νƒ€μž…μΌ ν•„μš”λŠ” μ—†λ‹€. μ—¬λŸ¬ νƒ€μž…μ— μž‘λ™ν•˜λŠ” μ˜€λ²„λ‘œλ”©λœ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ μ„œλ‘œ λ‹€λ₯Έ νƒ€μž…μ˜ λ³€μˆ˜λ₯Ό λ°”μΈλ”©ν•˜λŠ” νŒ¨ν„΄μ— κ³΅ν†΅μœΌλ‘œ μž‘λ™ν•˜λŠ” ν•˜λ‚˜μ˜ κ²°κ³Ό 식을 μž‘μ„±ν•  수 μžˆλ‹€.

def stringy : Nat βŠ• Weekday β†’ String | .inl x | .inr x => s!"It is {repr x}"

μ‹€μ œλ‘œλŠ” λͺ¨λ“  νŒ¨ν„΄μ— 곡유된 λ³€μˆ˜λ§Œ κ²°κ³Ό μ‹μ—μ„œ μ°Έμ‘°ν•  수 μžˆλ‹€. 각 νŒ¨ν„΄μ— λŒ€ν•΄ κ²°κ³Όκ°€ μ˜λ―Έκ°€ μžˆμ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. getTheNatμ—μ„œλŠ” n만 μ ‘κ·Όν•  수 있으며 xλ‚˜ yλ₯Ό μ‚¬μš©ν•˜λ € ν•˜λ©΄ 였λ₯˜κ°€ λ‚œλ‹€.

def getTheNat : (Nat Γ— Ξ±) βŠ• (Nat Γ— Ξ²) β†’ Nat | .inl (n, x) | .inr (n, y) => n

λΉ„μŠ·ν•œ μ •μ˜μ—μ„œ x에 μ ‘κ·Όν•˜λ € ν•˜λ©΄ 두 번째 νŒ¨ν„΄μ—λŠ” xκ°€ μ—†μœΌλ―€λ‘œ 였λ₯˜κ°€ λ‚œλ‹€.

def getTheAlpha : (Nat Γ— Ξ±) βŠ• (Nat Γ— Ξ±) β†’ Ξ± | .inl (n, x) | .inr (n, y) => Unknown identifier `x`x
Unknown identifier `x`

νŒ¨ν„΄ 맀칭의 각 뢄기에 κ²°κ³Ό 식을 사싀상 볡사해 λΆ™μΈλ‹€λŠ” 점 λ•Œλ¬Έμ— λ†€λΌμš΄ λ™μž‘μ΄ 생길 수 μžˆλ‹€. 예λ₯Ό λ“€μ–΄ λ‹€μŒ μ •μ˜λŠ” κ²°κ³Ό μ‹μ˜ inr 버전이 μ „μ—­ μ •μ˜μΈ strλ₯Ό μ°Έμ‘°ν•˜λ―€λ‘œ ν—ˆμš©λœλ‹€.

def str := "Some string" def getTheString : (Nat Γ— String) βŠ• (Nat Γ— Ξ²) β†’ String | .inl (n, str) | .inr (n, y) => str

두 μƒμ„±μžμ— 이 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ ν˜Όλž€μŠ€λŸ¬μš΄ λ™μž‘μ΄ λ“œλŸ¬λ‚œλ‹€. 첫 번째 κ²½μš°μ—λŠ” Ξ²κ°€ μ–΄λ–€ νƒ€μž…μ΄μ–΄μ•Ό ν•˜λŠ”μ§€ Lean에 μ•Œλ € μ£ΌλŠ” νƒ€μž… 주석이 ν•„μš”ν•˜λ‹€.

"twenty"#eval getTheString (.inl (20, "twenty") : (Nat Γ— String) βŠ• (Nat Γ— String))
"twenty"

두 번째 κ²½μš°μ—λŠ” μ „μ—­ μ •μ˜κ°€ μ‚¬μš©λœλ‹€.

"Some string"#eval getTheString (.inr (20, "twenty"))
"Some string"

Weekday.isWeekend처럼 or νŒ¨ν„΄μ„ μ‚¬μš©ν•˜λ©΄ 일뢀 μ •μ˜λ₯Ό 크게 κ°„μ†Œν™”ν•˜κ³  λͺ…ν™•ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€. ν˜Όλž€μŠ€λŸ¬μš΄ λ™μž‘μ΄ 생길 κ°€λŠ₯성이 μžˆμœΌλ―€λ‘œ, 특히 μ—¬λŸ¬ νƒ€μž…μ˜ λ³€μˆ˜λ‚˜ μ„œλ‘œ κ²ΉμΉ˜μ§€ μ•ŠλŠ” λ³€μˆ˜ 집합이 κ΄€λ ¨λœ κ²½μš°μ—λŠ” μ£Όμ˜ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.