Yeah, I think the problem here is that you want one function value that's generic over its input type. Instead, this pack expansion:
predicate: repeat (each Element) -> Bool
means that you're passing in separate function values - one for each Element type in the argument pack. So, in your "meta-predicate" here:
func isSome<each Wrapped>() -> (repeat ((each Wrapped)?) -> Bool) {
...
}
You're not returning a single generic function value; you're returning N function values stored in a tuple. The reason why you're getting an error here:
predicate: isSome // Command SwiftCompile failed with a nonzero exit code
is because you're trying to pass a tuple containing these function values, but the allSatisfy function actually expects separate arguments. Obviously this should emit an error instead of crashing, but this appears to be fixed on main (I got a compiler error locally for this code)
Allowing a general tuple expansion operation for concrete tuples would fix this issue, or you can write it today by passing in separate closures:
public func allSatisfy<each Element>(
_ element: repeat each Element,
predicate: repeat (each Element) -> Bool
) -> Bool {
var allSatisfy = true
repeat (each predicate)(each element) ? () : (allSatisfy = false)
return allSatisfy
}
print(allSatisfy(1, "hello", nil as Bool?, predicate: { $0 != nil }, { $0 != nil }, { $0 != nil }))
This compiles locally for me, and it prints false. It's obviously not good that you have to repeat the predicate N times when really you want the same code for each element in the pack. Instead, I think the best way to express this right now is with a functor-style object, where you actually can write the predicate as a generic function:
func allSatisfy<each Element, Predicate: Functor> (
_ element: repeat each Element,
predicate: Predicate
) -> Bool where Predicate.Result == Bool {
var allSatisfy = true
repeat predicate.evaluate(each element) ? () : (allSatisfy = false)
return allSatisfy
}
protocol Functor {
associatedtype Result
func evaluate<T>(_: T) -> Result
}
protocol OptionalProtocol {
var isNil: Bool { get }
}
extension Optional: OptionalProtocol {
var isNil: Bool {
switch self {
case .some: false
case .none: true
}
}
}
struct IsSome: Functor {
func evaluate<T>(_ value: T) -> Bool {
switch value {
case let optional as any OptionalProtocol: optional.isNil
default: false
}
}
}
print(allSatisfy(1, "hello", nil as Bool?, predicate: IsSome())) // prints 'false'
This forces you to write all of your predicate code in a generic context, so e.g. checking for nil becomes harder, but the same would be true if Swift supported generic closures.