JD-man / TIL

0 stars 0 forks source link

Currying #11

Open JD-man opened 2 years ago

JD-man commented 2 years ago

정의

예시

Currying 이전

func aHigherOrderFunction(_ operation: (Int) -> ()) {
  let numbers = 1...10
  numbers.forEach(operation)
}

func someOperation(_ p1: Int, _ p2: String) {
  print("number is: \(p1), and String is: \(p2)")
}

aHigherOrderFunction { someOperation($0, "a constant") }

Currying 이후

func curried_SomeOperation(_ p1: Int) -> (String) -> () {
  return { str in
    print("number is: \(p1), and String is: \(str)")
  }
}
aHigherOrderFunction { curried_SomeOperation($0)("a constant") }

Flipping

func curried_SomeOperation(_ str: String) -> (Int) -> () {
  return { p1 in
    print("number is: \(p1), and String is: \(str)")
  }
}

aHigherOrderFunction(curried_SomeOperation("a constant"))
JD-man commented 2 years ago

A generic currying function

func curry<A, B, C>(
  _ originalMethod: @escaping (A, B) -> C
) -> (A) -> (B) -> C {
  return { a in
    { b in
      originalMethod(a, b)
    }
  }
}
someOperation(1, "number one")
curry(someOperation)(1)("number one")
JD-man commented 2 years ago

Generic argument flipping

func flip<A, B, C>(
  _ originalMethod: @escaping (A) -> (B) -> C
) -> (B) -> (A) -> C {
  return { b in { a in originalMethod(a)(b) } }
}
let curried = curry(someOperation)
let flipped = flip(curried)
aHigherOrderFunction(flipped("a constant"))
JD-man commented 2 years ago

Class Method Flipping

extension Int {
  func word() -> String? {
    let formatter = NumberFormatter()
    formatter.numberStyle = .spellOut
    return formatter.string(from: self as NSNumber)
  }
}

[1, 2, 3, 4, 5].map { $0.word() }
// [Optional("one"), Optional("two"), Optional("three"), Optional("four"), Optional("five")]

Class Method

Int.word 
// (Int) -> () -> Optional<String>

Int.word(1)() // one
Int.word(10)() // ten
Int.word(36)() // thirty-six
func flip<A, C>(
  _ originalMethod: @escaping (A) -> () -> C
) -> () -> (A) -> C {
  return { { a in originalMethod(a)() } }
}
var flippedWord = flip(Int.word)()
[1, 2, 3, 4, 5].map(flippedWord)
// ["one", "two", "three", "four", "five"]
func reduce<A, C>(
  _ originalMethod: @escaping (A) -> () -> C
) -> (A) -> C {
  return { a in originalMethod(a)() }
}

var reducedWord = reduce(Int.word)
JD-man commented 2 years ago

Generic Function Merger

func mergeFunctions<A, B, C>(
  _ f: @escaping (A) -> () -> B,
  _ g: @escaping (B) -> () -> C
) -> (A) -> C {
  return { a in
    let fValue = f(a)()
    return g(fValue)()
  }
}

func +<A, B, C>(
  left: @escaping (A) -> () -> B,
  right: @escaping (B) -> () -> C
) -> (A) -> C {
  return { a in
    let leftValue = left(a)()
    return right(leftValue)()
  }
}
extension Int {
  func word() -> String? {
    let formatter = NumberFormatter()
    formatter.numberStyle = .spellOut
    return formatter.string(from: self as NSNumber)
  }

  func squared() -> Int {
    return self * self
  }
}

var mergedFunctions = mergeFunctions(Int.squared, Int.word)
mergedFunctions(2) // four

var addedFunctions = Int.squared + Int.word
addedFunctions(2) // four
(Int.squared + Int.word)(2) // four