본문 바로가기
아이폰 개발/Swift

swift 함수형 프로그래밍 정리

by 인생여희 2021. 9. 28.

swift 함수형 프로그래밍 정리

 

 

1.순수함수

 

1.함수의 동작이 외부에 있는 변수에 영향을 받거나 주지 않는다.

2.특정 input에 대해서 항상 동일한 output을 낸다.

3.특정 입력값에 대해서 항상 동일한 결과를 낸다.

 

 

문제 1 - 주어진 코드에서 외부변수를 사용하지 않는 순수함수로 변경하세요

 

var sum = 0
func solution(_ nums: [Int]) -> Int {
    for i in nums {
        sum += i
    }
    return sum
}

let nums = [1,2,3,4,5]
let numAddRst = solution(nums)
print("numAddRst : \(numAddRst)")
//numAddRst : 15

 

풀이 1 - 전역변수 sum을 함수안으로 옮겨서 지역변수로 만들어 주었다.

func solution_S(_ nums:[Int]) -> Int {
    var sum_ = 0
    for i in nums {
        sum_ += i
    }
    return sum_
}
let numAddRst_S = solution_S(nums)
print("numAddRst_S : \(numAddRst_S)")
//numAddRst_S : 15

 

 

2. 고차함수

 

함수를 파라미터로 받거나 함수를 리턴하는 함수를 고차함수라고 한다.

swift 에서는 함수를 1급 객체로 취급한다.

 

함수를 파라미터로 전달하는 예

let arr = [1,2,3,4,5]
func isEven(_ i:Int) -> Bool{
    return i % 2 == 0
}
let evens = arr.filter(isEven)
print("evens: \(evens)")
//evens: [2, 4]

let evens2 = arr.filter { i in
    i % 2 == 0
}
print("evens2: \(evens2)")
//evens2: [2, 4]

 

 

함수를 리턴하는 함수

func multiply(_ a:Int) -> (Int) -> Int {
    
    func multi(_ b:Int) -> Int {
        return a * b
    }
    
    return multi
}

let area = multiply(10)(20)
print("area: \(area)")
//area: 200



func multiply2(_ a:Int) -> (Int) -> Int {
    return { b in a * b }
}

let x10 = multiply(10)
let area2 = x10(20)
print("area2: \(area2)")
//area2: 200

 

 

문제 2 - 고차함수를 사용하여 짝수만의 합을 계산합니다.  f, s 의 함수 내부를 구현하세요

let nums2 = [1,2,3,4,5,6,7,8,9,10]

let f: (Int) -> Bool = { }
let s: (Int, Int) -> Int = { }

func solution2(_ nums: [Int]) -> Int {
    return nums.filter(f).reduce(0, s)
}

 

풀이 2

 

//func s (a:Int, b:Int) -> Int{ return a*b }

let nums2 = [1,2,3,4,5,6]
let f: (Int) -> Bool = { $0 % 2 == 0 }
let s: (Int , Int) -> Int = { a, b in
    return a+b
}
func solution2(_ nums: [Int]) -> Int {
    return nums.filter(f).reduce(0, s)
}

let addSolutionResult = solution2(nums2)
print("addSolutionResult : \(addSolutionResult)")
//addSolutionResult : 12

 

 

3.함수의 합성(Composition)

 

함수의 반환값이 다른 함수의 입력값으로 사용되는것

함수의 반환값과 이것을 입력으로 받아들이는 값은 타입이 같아야한다.

 

함수의 합성 기본

func comReturnInt(_ i:Int) -> Int{
    return i * 2
}

func comReturnString(_ i:Int) -> String{
    return "\(i)"
}

// comReturnInt함수의 수행결과가 comReturnString 함수의 인자로 사용되었다.
let comResult = comReturnString(comReturnInt(200))
print("comResult : \(comResult)")
// comResult : 400

 

고차함수 이용해서 함수를 합성하는 함수 만들기

// cp1, cp2는 compositFuncs 함수가 반환된 이후에 실행되기 때문에 @escaping 선언을 해준다.
func compositFuncs(_ cp1: @escaping (Int) -> Int , _ cp2: @escaping (Int) -> String ) -> (Int) -> String {

    return { paramAInt in
        cp2(cp1(paramAInt))
    }
}

let comFuncResult = compositFuncs(comReturnInt, comReturnString)
let comResult2 = comFuncResult(200)
print("comResult2 : \(comResult2)")
// comResult2 : 400


// generic을 사용해서 범용적인 합성함수 생성 함수만들기
func compositFuncsGeneric<A,B>(_ cp1: @escaping (A)->A , _ cp2: @escaping (A)->B) -> (A)->B{
    return { paramAInt in
        cp2(cp1(paramAInt))
    }
}

let comFuncResultWithGeneric = compositFuncsGeneric(comReturnInt, comReturnString)
let comResult3 = comFuncResultWithGeneric(200)
print("comResult3 : \(comResult3)")
// comResult3 : 400

 

문제 3 - 아래는 짝수만의 합을 계산하는 코드입니다. 함수의 합성을 이용하여 완성하세요.

import Foundation

 let nums3 = [1,2,3,4,5,6]
 
 func comp3<A, B>(_ pf1: @escaping (A) -> A,
                    _ pf2: @escaping (A) -> B) -> (A) -> B {
     return { i in
         return pf2(pf1(i))
     }
 }

 func filterEven3(_ ns: [Int]) -> [Int] {
     //함수를 구현하세요
 }

 func sum3(_ ns: [Int]) -> Int {
     //함수를 구현하세요
 }

 let filteredSum3 = comp3(filterEven3, sum3)

 func solution3(_ nums: [Int]) -> Int {
     return filteredSum3(nums3)
 }

 

 

풀이 3

let nums3 = [1,2,3,4,5,6]


// 짝수 구하기
func filterEven3(_ ns:[Int]) -> [Int] {
    let result = ns.filter { intA in
        intA % 2 == 0
    }
    return result
}

// 합계 구하기
func sum3 (_ ns:[Int]) -> Int {
    let result = ns.reduce(0, { a, b in a + b })
    return result
}

// 짝수구하기함수 + 합계구하기 함수 = 짝수합계함수 생성
func addFilterEven3AndSum3Func<A,B>(_ filterFunc:(A) -> A , _ sumFunc:(A)->B ) -> (A) -> B{
    return {
        paramArray in
        sum3(filterEven3(paramArray as! [Int])) as! B
    }
}

let evenSumFunc = addFilterEven3AndSum3Func(filterEven3, sum3)

func solution3(_ nums:[Int]) -> Int {
    return evenSumFunc(nums)
}

print("solution3 result : \(solution3(nums3))" )
// solution3 result : 12

 

 

4.커링(Currying)

의미 : 여러개의 파라미터를 받는 하나의 함수를 하나의 파라미터를 받는 여러개의 함수로 쪼개는 기법

목적 : 함수의 output이 다른 함수의 input 으로 연결되면서 함수의 합성이 일어난다.

합성이 될려면 함수의 output과 input의 타입과 개수가 같아야 한다.

함수의 output은 하나 밖에 없으니 input도 한개라면 합성이 쉬워진다.

즉, 함수의 합성을 원할하게 하기위해서 커링을 사용한다.

 

예제

func func4(_ a:Int, _ b:Int) -> Int{
    return a * b
}


// func func4_1(_ a:Int) -> Int { return 0 }
// func func4_2(_ a:Int) -> Int { return 0 }


func multiply4(_ a:Int) -> (Int) -> Int {
    return {
       b in return a * b
    }
}

let multiply4Result = multiply4(10)(20)
print("multiply4Result  : \(multiply4Result)" )
// multiply4Result  : 200

 

문제 4.  - n의 배수만을 모아 합을 구하는 함수 filterSum을 currying 하여 filterSum4를 만드세요.

import Foundation

 let nums4 = [1,2,3,4,5,6]

 func filterSum(_ ns: [Int], _ n: Int) -> Int {
     return ns.filter({ $0 % n == 0 }).reduce(0, +)
 }

 func filterSum4(_ n: Int) -> ([Int]) -> Int {
     //함수를 구현하세요
 }

 func solution(_ nums: [Int], _ r: Int) -> Int {
     let filteredR = filterSum4(r)
     return filteredR(nums4)
 }

 

풀이 4

func filterSum4(_ n: Int) -> ([Int]) -> Int {
    return { intArray in
        intArray.filter({ $0 % n == 0}).reduce(0, { a, b in a + b})
    }
}

let nums4 = [1,2,3,4,5,6]

func solution4(_ nums: [Int] ,  _ r: Int) -> Int {
    let filteredR = filterSum4(r)
    return filteredR(nums4)
}

let filterSum4Result =  solution4(nums4, 2)
print("filterSum4Result  : \(filterSum4Result)" )
// filterSum4Result  : 12

 

 

참고

https://www.inflearn.com/course/swift-fp/dashboard

 

 

main.swift
0.01MB