xiaolingxiao
xiaolingxiao

Reputation: 4895

Using higher order functions in swift

I am learning swift coming from a Haskell background, I would like to translate this bit into swift:

match :: Int -> Bool
match = (>) 3

hasMatch :: (Int -> Bool) -> [Int] -> [Int]
hasMatch pred ns = filter pred ns

hasMatch match [1..5] = [4,5]

Silly example I know. This is what I have with swift:

func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
    return ns.filter{n in pred(n:n)}
}


func match(n: Int) -> Bool{
    return n > 3
}

let os = hasMatch(pred : match, ns: [1,2,3,4,5])

Which does not compile. This is the error message:

let os = hasMatch(pred : match, ns: [1,2,3,4,5])

    ./hello-swift.swift:48:28: error: extraneous argument label 'n:' in call
        return ns.filter{n in pred(n:n)}
                                  ^~~

./hello-swift.swift:48:24: error: closure use of non-escaping parameter 'pred' may allow it to escape
        return ns.filter{n in pred(n:n)}
                              ^
./hello-swift.swift:47:15: note: parameter 'pred' is implicitly non-escaping
func hasMatch(pred : (Int) -> Bool, ns : [Int]) -> [Int]{
              ^
                     @escaping 

I have two questions:

  1. I have pred(n:n) but this assumes that pred names its input as n, which does not make sense. Do all functions have to have named inputs?

  2. How would I change to the code so that it compiles

Upvotes: 0

Views: 1390

Answers (2)

Sachin Daingade
Sachin Daingade

Reputation: 11

func mapedData(){
let bookData = ["book1":120, "book2": 150]
let mapedData = bookData.map({(key,value) in return value + 40 })
print(mapedData)
}

// [160, 190]

func filterData()
{
     let bookData = ["book1":127, "book2": 150 ,"book3": 289 ,"book4": 190, "book5": 950  ]
    let filterData = bookData.filter({(key,value) in return value < 200})
    print(filterData)
}

// ["book2": 150, "book4": 190, "book1": 127]

func reducedData()
{
    let data = [1,2,3,4,5,6,7,8,9,10]
    let reducedData = data.reduce(0, { sum , number in return sum + number })
    print(reducedData)
}

//55

func compactData(){
       let data = [1,nil,3,4,5,6,7,nil,9,10]
    let cMap = data.compactMap({return $0})
    print(cMap)
}
// [1, 3, 4, 5, 6, 7, 9, 10]

func flatMappedData(){
    let data = ["sachin"]
    let characters = data.flatMap({return $0})
    print(characters)        
}

// ["s", "a", "c", "h", "i", "n"]

Upvotes: 0

deanWombourne
deanWombourne

Reputation: 38475

func hasMatch(pred: (Int) -> Bool, ns: [Int]) -> [Int] {
    return ns.filter { n in pred(n) }
}

You don't need parameter names if the function is a closure.

@escaping is a keyword in swift which tells the compiler that the passed in function will escape the current scope, so it needs to retain/release the passed in arguments (Swift, like objective-c, uses retain counting for memory management)

However, you don't need it in this case - that error was a red herring thrown by the compiler because it couldn't compile the line with filter in, so it didn't know whether you needed to escape or not. Looks like it plays things safe :)

As soon as you remove the n: and it can work out which filter you are calling, it knows that because filter doesn't need an @escaping closure, your method doesn't either so that error goes away.

Upvotes: 3

Related Questions