swiftfunctional-programmingnot-operator

Swift: use not operator functionally


I would like to get the opposite of a boolean value using dot syntax.

E.g.

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains)
// Cannot convert value of type '(Int) -> Bool' to expected argument type 'Bool'

The following code works, however.

let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
let notFives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.contains)
// [1, 2, 3, 4, 6, 7, 8, 9]

I need to get the opposite value functionally using the not operator. If it's possible I would like not to have to define a bool extension or custom operator just to do so.

How can you do this in Swift?


Solution

  • I would just extend Sequence protocol constraining Element to Equatable and implement a notContains method:

    extension Sequence where Element: Equatable {
        func notContains(_ element: Element) -> Bool { !contains(element) }
    }
    

    let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
    let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(digitsExceptForFive.notContains)  // [5]
    

    You can also extend Bool and provide a negated property, this would allow to use negated KeyPath syntax:

    extension Bool {
        var negated: Bool { !self }
    }
    

    let string = "abc12345" 
    let nonDigits = string.filter(\.isWholeNumber.negated) // "abc"
    

    if you really want to implement a custom prefix operator (I really prefer using the notConstains method and the Bool negated instance property) you can do something like:

    prefix func !<T>(predicate: @escaping (T) -> Bool) -> (T) -> Bool { { !predicate($0) } }
    

    Usage:

    let string = "abc12345"
    let nonDigits = string.filter(!\.isWholeNumber) // "abc"
    
    let digitsExceptForFive = [1, 2, 3, 4, 6, 7, 8, 9]
    let fives = [1, 2, 3, 4, 5, 6, 7, 8, 9].filter(!digitsExceptForFive.contains) // [5]