Swift: generic overloads, definition of "more specialized" - swift

In the below example, why is the foo(f) call ambiguous?
I understand that the second overload could also apply with P == (),
but why isn't the first one considered more specialized,
and therefore a better match?
func foo<R>(_ f: () -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
let f: () -> Int = { 42 }
foo(f) // "Ambiguous use of 'foo'"

I'd say your problem is that you don't explicitely tell the compiler that P == ()
try the following code in a playground :
Void.self == (Void).self // true
Void() == () // true
(Void)() == () // true
(Void) == () // Cannot convert value of type '(Void).Type' to expected argument type '()'
Foo<Int>.self == (() -> Int).self // false
(() -> Int).self == ((Void) -> Int).self // false
Foo<Int>.self == ((Void) -> Int).self // true
Since (Void) cannot be converted to (), I guess the compiler can't understand that foo<R>(_ f: () -> R) is actually a specialization of foo<P, R>(_ f: (P) -> R).
I suggest you create generic type aliases for your function types to help the compiler understand what you're doing eg. :
typealias Bar<P, R> = (P) -> R
typealias Foo<R> = Bar<Void, R>
Now you can can define your function like that :
func foo<R>(_ f: Foo<R>) { print("r") } // Note that this does not trigger a warning.
func foo<P, R>(_ f: Bar<P, R>) { print("pr") }
and then use them with any closure you want :
let f: () -> Int = { 42 }
foo(f) // prints "r"
let b: (Int) -> Int = { $0 }
foo(b) // prints "pr"
let s: (String) -> Double = { _ in 0.0 }
foo(s) // prints "pr"
But you can actually just write :
func foo<R>(_ f: (()) -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
or even :
func foo<R>(_ f: (Void) -> R) { print("r") } // triggers warning :
// When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?
func foo<P, R>(_ f: (P) -> R) { print("pr") }
and you get the same results.

Related

Generic parameter 'Arg' could not be inferred - generic memoization function

I'm trying to build a generic memoization function
func memoize<Arg: Hashable, Ret>(_ fn: #escaping ((Arg) -> Ret)) -> ((Arg) -> Ret) {
var cache: [Arg:Ret] = [:]
func inner (x: Arg) -> Ret {
let ret = cache[x, default: fn(x)]
cache[x] = ret
return ret
}
return inner
}
But I am unable to define my function as a closure for some reason
struct Foo: Hashable {
let a: String
let b: String
}
let foo = memoize(
(x: Foo) -> String in {
print("miss")
return x.a
}
)
Cannot convert value of type '((Foo) -> String).Type' to expected argument type '(Arg) -> Ret'
Generic parameter 'Arg' could not be inferred
why is that?
Your closure syntax is incorrect. The signature part goes inside of the { } (See Closure Expression Syntax):
let foo = memoize(
{ (x: Foo) -> String in
print("miss")
return x.a
}
)
You can also omit the () (known as a trailing closure), which is more idiomatic:
let foo = memoize {
(x: Foo) -> String in
print("miss")
return x.a
}

Ignore "unused" warning in Swift when use a "pointer" to func?

I know that I should use #discardableResult. So I have the following code:
#discardableResult func someFunc() { ... }
Then I just call it:
someFunc()
But if I have and use a pointer to this method then it doesn't work again. For example:
let someFunc = self.someFunc
someFunc() //unused warning
Is it possible to avoid _=someFunc() in this case?
Unfortunately, discardableResult only applies to method/function declarations. What you can do is to wrap the value-returning function in a void-returning closure:
#discardableResult
func f() -> Int { return 1 }
// the type annotation here is important
let someFunc: () -> Void = { f() }
Alternatively, write a function that "erases" the return type of functions:
func discardResult<R>(_ f: #escaping () -> R) -> (() -> Void) {
{ _ = f() }
}
let someFunc = discardResult(f)
The downside is that you need to write an overload of this for each arity:
func discardResult<T, R>(_ f: #escaping (T) -> R) -> ((T) -> Void) {
{ x in _ = f(x) }
}
func discardResult<T, U, R>(_ f: #escaping (T, U) -> R) -> ((T, U) -> Void) {
{ x, y in _ = f(x, y) }
}
func discardResult<T, U, V, R>(_ f: #escaping (T, U, V) -> R) -> ((T, U, V) -> Void) {
{ x, y, z in _ = f(x, y, z) }
}
// and so on

Is it possible to assign a generic function to a variable?

func function1(arg: Int) -> Int { return arg }
func function2<T>(arg: T) -> T { return arg }
let f1 = function1 // No problem
let f2 = function2<Int> // Cannot explicitly specialize a generic function
A current short coming of the language?
You can let Swift infer the specialization of function2 by the explicit type annotation of f2:
let f2: (Int) -> Int = function2
Alternatively, use an intermediate specializer function which supplies the explicit type annotation
func specialize1Dmap<T>(_ f: #escaping (T) -> T, as _: T.Type) -> (T) -> T { return f }
let f2int = specialize1Dmap(function2, as: Int.self)
let f2str = specialize1Dmap(function2, as: String.self)

curry function syntax in swift

I was going through this blog. When I tried write curry function on my own method:
func stdCurry(f : (A,B) -> C) -> (A)->(B->C) {
return { (a:A) ->(B -> C) in {
(b:B) -> C in
{
return f(a,b)
}
}
}
}
I got an error:
:7:22: error: declared closure result 'C' is incompatible with contextual type '_'
(b:B) -> C in
^
_
But when I remove the flower parentheses around trailing closure then it won't report any error. Can anybody help me to understand this.
The inner curly braces -> in { ... } tells swift that this inner part is a closure, whereas it in fact only contains a value (the C type evaluation of f(a,b)). If you remove these inner curly braces, your example work.
E.g., try
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B -> C) {
return { (a:A) -> (B -> C) in {
(b:B) -> C in
return f(a,b) // <-- this is not a closure (just returns a value of type C`
}
}
}
Note that I've added the generic types to the function signature above (perhaps you function is part of a class and you get your types A, B and C from there).
To make the error above more clear, consider this a bit simpler example (taking a closure and returning it):
/* This is ok */
func myClosure<A,B>(f: (A) -> B) -> (A) -> B {
return {
x in f(x)
}
}
/* Error: return type here is not (A) -> B, but contains
an anonymous closure () -> B */
func myClosure<A,B>(f: (A) -> B) -> (A) -> B {
return {
x in { f (x) }
}
}
/* Ok */
func myClosure<A,B>(f: (A) -> B) -> (A) -> (() -> B) {
return {
x in { f(x) }
}
}
Also note that since Swift knows (infers)---from your function signature---the types in as well as what type/closure to expect in return for each in ... statment, you can omit the closure type ((a:A) -> (B -> C)) as well as the return keyword and make your expression more compact as follows:
func stdCurry<A, B, C>(f: (A, B) -> C) -> A -> (B -> C) {
return { a in { b in f(a, b) } }
}
At your request in the comments below: you can make use of "multiple statements" in the tail e.g. by using the approach of the third "simple example" above, e.g.:
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B) -> () -> C {
return { (a:A) -> (B -> () -> C) in {
(b:B) -> () -> C in
return {
// ...
f(a,b)
}
}
}
}
Note that as the function signature grows somewhat "messy", it's favourable to omit these details in the actual closures of your function, i.e.:
func stdCurry<A,B,C>(f : (A,B) -> C) -> (A) -> (B) -> () -> C {
return { a in {
b in
return {
// ...
f(a,b)
}
}
}
}

Cannot invoke $function with object of type *

I'm having trouble with a type error that seems to be incorrect. The following code produces the error:
"Cannot invoke baz with argument list of type (f: (A) -> (), g: (String) -> ())" As indicated, the "incorrect" type is the exact type of baz, which is being called.
NB: I pulled out 'succeed' and 'fail' for type clarity, but the same thing happens when using the functions as closures.
class Foo<A> {
..
func baz(f: (A) -> (), g: (String) -> ()) {
.. do some stuff
}
func bar<A, B>(f: (A -> B)) -> Foo<B> {
func succeed(a: A) -> () {
.. do some stuff
}
func fail(s:String) -> () {
.. do some stuff
}
baz(f: succeed, g: fail)
.. do some stuff
}
}
Your generic parameter A declared for function bar overrides the generic type declared for class Foo, you need to remove it:
class Foo<A> {
func baz(f: (A) -> (), g: (String) -> ()) {}
func bar<B>(f: (A -> B)) -> Foo<B> {
func succeed(a: A) -> () {}
func fail(s:String) -> () {}
baz(succeed, g: fail)
return Foo<B>()
}
}
It's something about your A protocol. I changed and created new F so it could compile and it works in my playground:
protocol F {
}
class Foo<A> {
func baz(f: (F) -> (), g: (String) -> ()) {
}
func bar<A, B>(f: (A -> B)) -> Foo<B> {
func succeed(a:F) -> () {}
func fail(s:String) -> () {}
baz(succeed, g:fail)
return Foo<B>()
}
}