Как мне написать не / отрицать функцию высшего порядка в Swift? - PullRequest
0 голосов
/ 30 декабря 2018

Я Javascripter, и я люблю использовать функцию not/negate:

function not (predicateFunc) {
    return function () {
        return !predicateFunc.apply(this, arguments);
    };
}

Я пытаюсь сделать то же самое с swift:

func not <A> (_ f: @escaping (_ A: Any) -> Bool) -> (A) -> Bool {
    return { a in !f(a) }
}

Но я получаюошибки типа

generic parameter 'T' could not be inferred

и

Cannot convert value of type '(_) -> Bool' to expected argument type '(Any) -> Bool'

Результат, который я ищу, - это когда у меня есть такая функция:

func isEmpty<T: Collection>(collection: T) -> Bool {
    return collection.count == 0
}

Я могу просто создатьnotEmpty функция выглядит следующим образом:

let notEmpty = not(isEmpty)

А затем используйте ее как

   notEmpty([3,4,5]) // true

Что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

У вас есть две ошибки:

  • Вы используете A как параметр типа и как имя аргумента.
  • Вы используете Any какТип аргумента вместо использования параметра типа (A) в качестве типа аргумента.

Попробуйте это:

func not<A>(predicate: @escaping (A) -> Bool) -> (A) -> Bool {
    return { !predicate($0) }
}

Обратите внимание, что в этой версии я не используюимена аргументов для аргумента предиката.Вам не нужно имя аргумента в объявлении ((A) -> Bool), и я использую анонимное имя аргумента ($0) в теле.


Хорошо, так что вы хотите написатьthis:

func isEmpty<T: Collection>(collection: T) -> Bool {
    return collection.count == 0
}

func not<A>(_ predicate: @escaping (A) -> Bool) -> (A) -> Bool {
    return { !predicate($0) }
}

let notEmpty = not(isEmpty)

И вы получаете эту ошибку:

let notEmpty = not(isEmpty)
               ^ Generic parameter 'A' could not be inferred

Проблема в том, что этот код пытается создать универсальное замыкание, но Swift не поддерживает универсальные замыкания.

То есть, каким будет тип nonEmpty?Это будет что-то вроде:

<A: Collection>(A) -> Bool

, и Swift не поддерживает это.

0 голосов
/ 30 декабря 2018

Использование Any - это запах кода.Вы можете просто расширить коллекцию напрямую:

extension Collection {
    var notEmpty: Bool {
        return !isEmpty
    }
}

[1, 3, 5].notEmpty // true

Ваше функциональное определение not может работать так:

func not <A> (_ f: @escaping (_ a: A) -> Bool) -> (A) -> Bool {
    return { a in !f(a) }
}

Но для его вызова вам понадобится что-то вроде этого:

let arrayNotEmpty = not { (array: [Int]) in array.isEmpty }
arrayNotEmpty([1, 3, 5]) // true
...