0

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

xiaolingxiao
  • 4,793
  • 5
  • 41
  • 88
  • Closures lose their argument labels. It is just `return ns.filter{n in pred(n)}` – Martin R Jun 27 '17 at 15:32
  • Possible duplicate of https://stackoverflow.com/questions/39613272/xcode-8-function-types-cannot-have-argument-label-breaking-my-build or https://stackoverflow.com/questions/41514014/why-apples-closure-declarations-missing-argument-labels. – Martin R Jun 27 '17 at 15:33

2 Answers2

3
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.

deanWombourne
  • 38,189
  • 13
  • 98
  • 110
  • @MartinR Just realized that - check out my edit! Thought it looked wrong, but couldn't put my finger on why. That'll teach me to blindly follow the autofix button in Xcode! – deanWombourne Jun 27 '17 at 16:26
  • @Martin R I'm sorry could you explain why I don't need parameter names if a function is a closure? I am very confused about this whole parameter name thing. – xiaolingxiao Jun 27 '17 at 17:42
  • @chibro2: It is a consequence of https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md. Have a look at the two Q&A's that I linked-to above. – Martin R Jun 27 '17 at 17:46
0
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"]