ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TCA] Episodes 1 - Functions
    TCA/Episodes 2023. 5. 6. 18:09

    Introduce

    Point-Free๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ Swift๋ฅผ ๋‹ค๋ฃจ๋Š” ๋น„๋””์˜ค ์‹œ๋ฆฌ์ฆˆ์ž…๋‹ˆ๋‹ค.

    ์—ฌ๊ธฐ์„œ๋Š” ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ ๋งŽ์ด ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์—, ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด์„œ ์ž˜ ์•Œ์•„๋‘ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    Swift์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ free function์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

    ์™œ๋ƒ?! free function์€ global namespace์— ๋– ๋‹ค๋‹ˆ๊ณ , ํƒ€์ž…์— ๋ฌถ์—ฌ์žˆ์ง€ ์•Š์•„์„œ messyํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ๋Š” free function์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

     

    ์ฐธ๊ณ ๋กœ ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” free function์ด๋ž€, ๋ฉค๋ฒ„ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

    struct NotFreeFunction {
    	func hi() { } // Not Free Function
    }
    
    func bye() { } // Free Function
    func byeee() -> Int { return 1 } // Free Function

     

    |> ์—ฐ์‚ฐ์ž (ํŒŒ์ดํ”„ ์—ฐ์‚ฐ์ž)

    ์™ผ์ชฝ์€ A ํƒ€์ž…์˜ ๊ฐ’์ด๊ณ  ์˜ค๋ฅธ์ชฝ์€ A์—์„œ B๋กœ์˜ ํ•จ์ˆ˜๋กœ, ๊ฐ’ A์— ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด์„œ B๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    precedencegroup ForwardApplication {
      associativity: left
    }
    
    infix operator |>: ForwardApplication // ์™ผ์ชฝ์˜ ํ‘œํ˜„์‹์„ ๋จผ์ € ํ‰๊ฐ€
    
    func |> <A, B>(a: A, f: (A) -> B) -> B {
    	return f(a)
    }
    
    func incr(_ x: Int) -> Int {
      return x + 1
    }
    
    print(2 |> incr) // 3
    print(2 |> incr |> square) // 9

     

    ์—ฐ์‚ฐ์ž ์ •์˜ ์กฐ๊ฑด

    1. ๊ธฐ์กด์— ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š” ์—ฐ์‚ฐ์ž์— ์ƒˆ๋กœ์šด ์˜๋ฏธ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ overload๋ฅผ ์ผ์œผ์ผœ์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.
    2. ๊ฐ€๋Šฅํ•œ ํ•œ ์„ ํ–‰ ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜๊ณ , ์—ฐ์‚ฐ์ž๊ฐ€ ๊ทธ ์˜๋ฏธ๋ฅผ ์—ฐ์ƒ์‹œํ‚ค๋Š” ๋ฉ‹์ง„ ๋ชจ์–‘์„ ๊ฐ–๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
      • ์•ž์„œ ์ •์˜ํ•œ |> ์—ฐ์‚ฐ์ž์˜ ๊ฒฝ์šฐ, ๊ฐ’์„ ํ•จ์ˆ˜์— ์ „๋‹ฌํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ |>๋Š” F#, Elixir, Elm์—์„œ ์ด๋ฏธ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
    3. ๋งค์šฐ ํŠน์ •ํ•œ ๋„๋ฉ”์ธ์— ๊ตญํ•œ๋œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ์—ฐ์‚ฐ์ž๋ฅผ ๋งŒ๋“ค์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๋งค์šฐ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ , ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์—ฐ์‚ฐ์ž๋งŒ ์ •์˜ํ•˜๊ณ  ๋„์ž…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์•ž์„œ ์ •์˜ํ•œ |> ์—ฐ์‚ฐ์ž๋Š” ์œ„์˜ 3๊ฐ€์ง€ ์กฐ๊ฑด์„ ๋ชจ๋‘ ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค.

     

    >>> ์—ฐ์‚ฐ์ž

    ํ•จ์ˆ˜ ํ•ฉ์„ฑ ์—ฐ์‚ฐ์ž๋กœ, ํ•œ ํ•จ์ˆ˜์˜ ์ถœ๋ ฅ์ด ๋‹ค๋ฅธ ํ•จ์ˆ˜์˜ ์ž…๋ ฅ์— ์ผ์น˜ํ•˜๋„๋ก 2๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ•ฉ์„ฑํ•˜์—ฌ ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

    precedencegroup: ForwardComposition {
    	associativity: left
    	higherThan: ForwardApplication
    }
    
    infix operator >>>: ForwardComposition
    
    func >>> <A, B, C>(f: @escaping (A) -> B, g: @escaping (B) -> C) -> ((A) -> C) {
      return { a in
        g(f(a))
      }
    }
    

    3๊ฐœ์˜ generic ๋งค๊ฐœ๋ณ€์ˆ˜ (A, B, C)์— ๋Œ€ํ•œ generic ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

    A์—์„œ B๋กœ, B์—์„œ C๋กœ ์ „๋‹ฌํ•˜๋Š” 2๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , A์˜ ๊ฐ’์„ A๋ฅผ ์ทจํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•˜๋Š” ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ์ธ B๋ฅผ B๋ฅผ ์ทจํ•˜๋Š” ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ๋‘ ํ•จ์ˆ˜๋ฅผ ๋ถ™์ž…๋‹ˆ๋‹ค.

    >>> ์—ฐ์‚ฐ์ž ๋˜ํ•œ ์—ฐ์‚ฐ์ž ์ •์˜ ์กฐ๊ฑด 3๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค.

     

    ์œ„์˜ ์—ฐ์‚ฐ์ž๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    (square >>> incr)(3) // 10
    
    2 |> incr >>> square // 9
    

     

    ๋ฉ”์„œ๋“œ ํ•ฉ์„ฑ

    ๋ฉ”์„œ๋“œ ์„ธ๊ณ„์—์„œ function composition์„ ํ•˜๋ ค๋ฉด,

    ํƒ€์ž…์„ ํ™•์žฅํ•˜๊ณ  ๊ฐ ๋ฉ”์„œ๋“œ๋“ค์„ ํ•จ๊ป˜ ๊ตฌ์„ฑํ•˜๋Š” ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    extension Int {
    	func incrAndSquare() -> Int {
    		return self.incr().square()
    	}
    }
    
    2.incrAndSquare() // 9
    

     

    ๋ฐ˜๋ฉด, ํ•จ์ˆ˜ ํ•ฉ์„ฑ (function composition)์€ ์•„์ฃผ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

    incr >>> square
    

     

    ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ์ž‘์€ ๊ตฌ์„ฑ ์š”์†Œ๋“ค ํ•˜๋‚˜ ํ•˜๋‚˜ ๋ชจ๋‘ ๋‹ค ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    2 |> incr >>> square
    2 |> incr
    2 |> square
    incr >>> square
    

     

    ๋ฐ˜๋ฉด ๋ฉ”์„œ๋“œ๋Š” ๊ฐ’์ด ์—†์œผ๋ฉด ๋ฉ”์„œ๋“œ๋‚˜ ๋ฉ”์„œ๋“œ์˜ ํ•ฉ์„ฑ์„ ์ฐธ์กฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

    ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

    // valid
    2.incr().square()
    
    // invalid
    .incr().square()
    incr().square()
    

     

    ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” free function์„ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›๋Š” ์ˆ˜๋งŽ์€ ํ•จ์ˆ˜๋“ค์ด ์žˆ์Šต๋‹ˆ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋ฐฐ์—ด์—๋Š” map์ด๋ผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

    [1, 2, 3].map
    // (transform: (Int) throws -> T) rethrows -> [T]
    

    ์ด ๋ฉ”์„œ๋“œ๋Š” ๋ฐฐ์—ด์˜ ์›์†Œ ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ํƒ€์ž… T๋กœ free function์„ ๊ฐ€์ ธ์™€์„œ ๋ณ€ํ™˜ํ•˜๊ณ  T ์›์†Œ๋กœ ์ด๋ฃจ์–ด์ง„ ์ƒˆ๋กœ์šด ํƒ€์ž…์˜ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

     

    ์ผ๋ฐ˜์ ์œผ๋กœ ์ž„์‹œ ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฆ๋ถ„ํ•˜๊ณ  ์ œ๊ณฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    [1, 2, 3].map { ($0 + 1) * ($0 + 1) } // [4, 9, 16]
    

     

    ๋ฉ”์„œ๋“œ๋กœ๋งŒ ์ž‘์—…ํ•  ๋•Œ์—๋Š” ์žฌ์‚ฌ์šฉ์„ ํ”ผํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ํ•จ์ˆ˜๋กœ ์ž‘์—…ํ•˜๋ฉด, ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    [1, 2, 3]
      .map(incr)
      .map(square)
    // [4, 9, 16]
    

     

    ์ƒˆ๋กœ์šด ์ž„์‹œ ํ•จ์ˆ˜๋ฅผ ์—ด๊ฑฐ๋‚˜ ์ธ์ˆ˜๋ฅผ ์ง€์ •ํ•  ํ•„์š”๋„ ์—†์—ˆ๊ณ , ์ด๋ฅผ “point-free” ์Šคํƒ€์ผ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ฑฐ๋‚˜, ์ธ์ˆ˜๋ฅผ ์ง€์ •ํ•˜๊ฑฐ๋‚˜, ์‹ฌ์ง€์–ด $0๋ฅผ ์ง€์ •ํ•˜๋Š” ์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ฒƒ๋“ค์„ ๋ชจ๋‘ “points”๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

    “point-free” ์Šคํƒ€์ผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ•จ์ˆ˜์™€ ํ•ฉ์„ฑ์— ์ค‘์ ์„ ๋‘๊ธฐ ๋•Œ๋ฌธ์—, ์—ฐ์‚ฐ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฐธ์กฐํ•  ํ•„์š”์กฐ์ฐจ ์—†์Šต๋‹ˆ๋‹ค. ์ด ์‹œ๋ฆฌ์ฆˆ์˜ ์ด๋ฆ„๋„ ๋ฐ”๋กœ ์—ฌ๊ธฐ์„œ ๋”ฐ์˜จ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

     

    ๋ฐฐ์—ด์„ square๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์ „์—, incr๋กœ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์€ ํ•จ์ˆ˜ ํ•ฉ์„ฑ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

    ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ํ•œ ๋ฒˆ๋งŒ ๋งคํ•‘ํ•˜๊ณ , incr์„ square๋กœ forward-compose (์ˆœ๋ฐฉํ–ฅ ํ•ฉ์„ฑ)ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

    [1, 2, 3].map(incr >>> square) // [4, 9, 16]
    

     

    ์ด๋ฅผ ํ†ตํ•ด ๋ฉ”์„œ๋“œ์—์„œ๋Š” ๋ณด๊ธฐ ์–ด๋ ค์› ๋˜ composition ์—ฐ์‚ฐ์ž์™€ map์˜ ๊ด€๊ณ„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

    ์—ฌ๊ธฐ์„œ map์€ >>> ํ•ฉ์„ฑ ํ›„์— ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

     

    ๋‘ ํ•จ์ˆ˜์— ๊ฑธ์ณ map์„ ๋‘ ๋ฒˆ ํ•ฉ์„ฑํ•˜๋Š” ๊ฒƒ์€, map์— ๋Œ€ํ•œ ๋‘ ํ•จ์ˆ˜์˜ ํ•ฉ์„ฑ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    ์ด์™€ ๊ฐ™์€ ํŒจํ„ด์€ ๋งค์šฐ ๋งŽ๊ณ  ์•ž์œผ๋กœ๋„ ๊ณ„์† ์‚ดํŽด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

    ๊ฒฐ๋ก 

    ์˜ค๋Š˜์€ ์—ฌ๊ธฐ์„œ free function์œผ๋กœ global namespace๋ฅผ ์˜ค์—ผ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

    ๋ฉ”์„œ๋“œ๋กœ ํ•จ์ˆ˜๋ฅผ ํ•ฉ์„ฑํ•˜๋ ค๋ฉด, ๋งŽ์€ ์ž‘์—…๊ณผ ์ƒ์šฉ๊ตฌ๊ฐ€ ํ•„์š”ํ•˜๊ณ  ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค.

    ํ•˜์ง€๋งŒ ํ•จ์ˆ˜๋กœ ํ•ฉ์„ฑ์„ ํ•˜๋ฉด ํ›จ์”ฌ ๋” ํŽธ๋ฆฌํ•˜๋ฉฐ, ๊ฐ€๋…์„ฑ ๋˜ํ•œ ํ›จ์”ฌ ์ข‹๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์‹ค Swift๋Š” global namespace์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ํ•จ์ˆ˜์˜ ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ !

    • ํŒŒ์ผ์— ๋น„๊ณต๊ฐœ์ธ ํ•จ์ˆ˜ ์ •์˜ ๊ฐ€๋Šฅ
    • ๊ตฌ์กฐ์ฒด์™€ ์—ด๊ฑฐํ˜•์— ์ •์  ๋ฉค๋ฒ„์ธ ํ•จ์ˆ˜ ์ •์˜ ๊ฐ€๋Šฅ
    • ๋ชจ๋“ˆ๋กœ ๋ฒ”์œ„๊ฐ€ ์ง€์ •๋œ ํ•จ์ˆ˜ ์ •์˜ ๊ฐ€๋Šฅ. ๋™์ผํ•œ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์ •์˜ํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ชจ๋“ˆ ์ด๋ฆ„์œผ๋กœ ํ•œ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋ฅผ ๋‘๋ ค์›Œํ•˜์ง€ ๋งˆ์„ธ์š”!

    ์•ž์œผ๋กœ Point-Free์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

     

     

     

    Episode #0: We launched!

    Point-Free is here, bringing you videos covering functional programming concepts using the Swift language. Take a moment to hear from the hosts about what to expect from this new series.

    www.pointfree.co

     

    Episode #1: Functions

    Our first episode is all about functions! We talk a bit about what makes functions special, contrasting them with the way we usually write code, and have some exploratory discussions about operators and composition.

    www.pointfree.co

     

    ๋Œ“๊ธ€

Designed by Tistory.