extension Sequence {
// my operation that takes a predicate
func doIt(_ p: (Element, Element) -> Bool) {
// just for example, do this
forEach { print(" result: \(p($0, $0))") }
}
// pre-define some predicate for convenience
// Question: where is the best place to put this? Try to avoid define as global func
static func isConsecutive<T: BinaryInteger>(_ a: T, _ b: T) -> Bool { b - a == 1 }
}
// this do not compile:
[1, 2].doIt(Sequence.isConsecutive)
// Compile error:
// Protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements
// Static member 'isConsecutive' cannot be used on protocol metatype 'Sequence.Protocol'
// had to do it this way:
[1, 2].doIt([Int].isConsecutive)
// is there any better location to define `isConsecutive`
where is the best place to define my "prefab'ed" predicate func?
Since that predicate isn't tied to any particular type (or to sequences at all, really), defining it as a global function is your best bet. What's motivating trying to avoid making it global?
I guess you want default predicates to be suggested with dot notation. If so, you need to make them available as static properties/methods on a nominal type. You can define a Predicate type and have two overloads of doIt: one accepting closures and one accepting Predicates (I have mixed feelings about this approach though).
extension Predicate where Element: BinaryInteger {
static var allConsecutive: Predicate {
.init { p, n in n - p == 1 }
}
}
extension Predicate where Element: Collection, Element.SubSequence: Equatable {
static func allSamePrefix(ofMaxLength length: Int) -> Predicate {
.init { p, n in p.prefix(length) == n.prefix(length) }
}
}
With those extensions, with an array of Ints you will only get .allConsecutive, while with an array of Strings you will only get .allSamePrefix(ofMaxLength:).
So I am wrong in thinking my "predicate" func's belong to Sequence since my operation doIt is a func of Sequence. If the predicates are not really tied to Sequence, then they don't need to be name space inside Sequence. They can just be global and named with my prefix:
func doItIsConsecutive(...) -> Bool { .. }
I need to study @xAlien95 example and see if I can apply it to my code.