apple/Docs, iOS, Swift

[Swift] 커링(Currying)

lgvv 2023. 2. 28. 15:17

# Currying

함수형 프로그래밍을 위한 Currying 학습.

 

# 계기

 - SwiftUI를 사용하여 View를 모듈화를 시도.

 - 더 잘 만들기 위해 함수형 프로그래밍의 해당 개념에 대한 학습이 필요하다고 느낌.

 

# 목표

 - 간단한 덧셈 구현 (Level 1)

 - 정규표현식 구현 (Level 2)

 - Reduce, Map, Filter 구현

 - FlatMap, CompactMap 구현 (⚠️ 실패한 구현)

  : 기록하기 위해서 적어둠.

 

# 참고에서는 UI와 관련한 클로저를 함수형으로 받아서 간결하게 처리하는 예제도 있으니 확인하면 좋음.

 

❗️ 실패한 구현인 이유

 : 결과값이 다르게 나타남.

불완전 구현 (내장 함수와 다른 결과)

# 파일

SwiftCurrying.zip
0.03MB

 

# 간단한 덧셈 구현 (Level 1)

import Foundation

public class LEVEL1 {
    public func execute() {
        print(add(2, 3))
        print(curriedAdd(2)(3))
        print(curriedAdd2(2)(3))
        
        let stringDevideSlash = stringDevider("/")
        let stringDevideAsterisk = stringDevider("*")
        
        print(stringDevideSlash("aaa/bbb/ccc/ddd"))
        print(stringDevideAsterisk("aaa*bbb*ccc*ddd"))
        
    }
    
    public init() { }
    
    public func add(_ value1: Int, _ value2: Int) -> Int {
        return value1 + value2
    }
    
    // 두개의 Int 값을 받아서 덧셈을 하고 결과값을 리턴해주는 함수.
    public func curriedAdd(_ value1: Int) -> ( (Int) -> Int ) {
        return { value2 in
            return value1 + value2
        }
    }
    
    public func curriedAdd2(_ value1: Int) -> (Int) -> Int {
        return { value2 in
            return value1 + value2
        }
    }
    
    public func stringDevider(_ seperater: String) -> (String) -> [String] {
        return { (string: String) -> [String] in
            return string.components(separatedBy: seperater)
        }
    }
}

 

# 정규표현식 구현 (Level 2)

import Foundation

// MARK: - 클래스 형태로 사용

public class Regex {
    public func execute() {
        let regex = Regex("main")
        print(regex.test("int main()")) // true
        
        print(Regex("main").test("int main()")) // true
        
        print(Regex("xx").test("int main()")) // false
        print(Regex("t m").test("int main()")) // true
        print(Regex("tm").test("int main()")) // false
        
        print(Regex("main").test("int main()")) // true
        let hasMainIn = Regex("main").test
        
        print(hasMainIn("int main()")) // true
    }
    
    var internalExpression: NSRegularExpression?
    
    public init(_ pattern: String) {
        self.internalExpression = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    }
    
    public func test(_ input: String) -> Bool {
        let inputRange = NSMakeRange(0, input.count)
        guard let matchesCount = self.internalExpression?
            .matches(in: input, options: [], range: inputRange)
            .count else { return false }
        return matchesCount > 0
    }
}

// MARK: - 함수 형태로 사용

public func regexFunctionTest(pattern: String) -> (String) -> Bool {
    let expression: NSRegularExpression? = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive)
    
    return { (input: String) -> Bool in
        guard let expression = expression else { return false }
        let inputRange = NSMakeRange(0, input.count)
        let matches = expression.matches(in: input,
                                         options: [],
                                         range: inputRange)
        
        return matches.count > 0
    }
}

 

# Reduce, Map, Filter 구현

 

# Reduce

import Foundation

/*
 초기값을 지정하고, 각 원소를 어떻게 결합시킬지 정의하는 함수의 제네릭 형태
 */
public func customReduce<A, R>(
    xs: [A],
    initialResult: R,
    nextPartialResult: (R, A) -> R
) -> R {
    var result = initialResult
    
    for x in xs {
        result = nextPartialResult(result, x)
    }
    
    return result
}

public func sumUsingReduce(xs: [Int]) -> Int {
    return customReduce(xs: xs, initialResult: 0) { result, x in
        result + x
    }
}

public func conmbineUsingReduce(xs: [String]) -> String {
    return customReduce(xs: xs, initialResult: "") { result, x in
        result + x + " "
    }
}

extension Array {
    func customReduce<A, R>(
        initialResult: R,
        nextPartialResult: (R, A) -> R
    ) -> R {
        var result = initialResult
        
        for x in self {
            result = nextPartialResult(result, x as! A)
        }
        
        return result
    }
}

 

# Map

import Foundation

extension Array {
    public func customMap<A, R>(
        nextPartialResult: (A) -> R
    ) -> [R] {
        var result = [R]()
        
        for x in self {
            result.append(nextPartialResult(x as! A))
        }
        
        return result
    }
}

 

# Filter

import Foundation

extension Array {
    public func customFilter<A>(
        nextPartialResult: (A) -> Bool
    ) -> [A] {
        var result = [A]()
        
        for x in self where nextPartialResult(x as! A) {
            result.append(x as! A)
        }
        
        return result
    }
}

 

 

# FlatMap, CompactMap 구현

 

# FlatMap

import Foundation

extension Array {
    func customFlatMap<R: Sequence>(
        nextPartialResult: (Element) -> R?
    ) -> [R.Element] {
        var result = [R.Element]()
        
        for x in self {
            if let value = nextPartialResult(x) {
                result.append(contentsOf: value)
            }
        }
        
        return result
    }
    
    func customFlatMap<R>(
        nextPartialResult: (Element) -> R?
    ) -> [Element] {
        var result = [Element]()
        
        for xOrNil in self {
            result.append(xOrNil)
        }
        
        return result
    }
}

 

# CompactMap

import Foundation

extension Array {
    func customCompactMap<R: Sequence>(
        nextPartialResult: (Element) -> R?
    ) -> [R] {
        var result = [R]()
        
        for xOrNil in self {
            if let value = nextPartialResult(xOrNil) {
                result += [value]
            }
        }

        return result
    }
}

 

 

 

(참고)

https://academy.realm.io/kr/posts/currying-on-the-swift-functions/

 

Swift 함수에 커링 사용하기

다음: Realm Swift를 사용하면 iOS 앱 모델 레이어를 효과적으로 작성할 수 있습니다.

academy.realm.io

https://github.com/pointfreeco/swift-overture

 

GitHub - pointfreeco/swift-overture: 🎼 A library for function composition.

🎼 A library for function composition. Contribute to pointfreeco/swift-overture development by creating an account on GitHub.

github.com

https://thoughtbot.com/blog/introduction-to-function-currying-in-swift#no-seriously-though-what-is-currying

 

Introduction to Function Currying in Swift

Function currying in Swift might not be immediately obvious, but once you see the applications, it can be another incredibly powerful tool at your disposal.

thoughtbot.com

 

'apple > Docs, iOS, Swift' 카테고리의 다른 글

[WWDC23] Meet MapKit for SwiftUI  (0) 2023.06.18
[XCode 15.0 beta] Preview Macro Bug  (0) 2023.06.08
[iOS] UIImage.Orientation  (0) 2022.12.09
Swift HTML 코드 로드하기  (0) 2022.10.06
[Moya] Unable to parse empty data 대응하기  (0) 2022.09.29