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
}
Related
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.
I have a struct defined inside a function and would like define and use an overloaded operator on that struct:
func test() {
struct Foo {
let value: Int
static func +(left: Foo, right: Foo) -> Foo {
return Foo(value: left.value + right.value)
}
}
print(Foo(value: 2) + Foo(value: 3))
}
But this does not work and I get the following error:
test.swift:10:25: error: binary operator '+' cannot be applied to two 'Foo' operands
print(Foo(value: 2) + Foo(value: 3))
~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
test.swift:10:25: note: overloads for '+' exist with these partially matching parameter lists: (Float, Float), (Double, Double), (Float80, Float80), (UInt8, UInt8), (Int8, Int8), (UInt16, UInt16), (Int16, Int16), (UInt32, UInt32), (Int32, Int32), (UInt64, UInt64), (Int64, Int64), (UInt, UInt), (Int, Int), (String, String), (C, S), (S, C), (RRC1, RRC2), (Self, Self.Stride), (Self.Stride, Self), (UnsafeMutablePointer<Pointee>, Int), (Int, UnsafeMutablePointer<Pointee>), (UnsafePointer<Pointee>, Int), (Int, UnsafePointer<Pointee>)
print(Foo(value: 2) + Foo(value: 3))
^
Is it just not suppoerted to define operators on non-global structs or am I missing something? Are there any options to make this work without moving the struct to the file scope?
You can't declare a struct with overload and then use it in the same function. In compilation time, the overload will not be known.
So you have to put the struct outside the function like this
struct Foo{
let value: Int
static func +(lhs: Foo, rhs: Foo) -> Foo {
return Foo(value: lhs.value + rhs.value)
}
}
func test() {
print(Foo(value: 2) + Foo(value: 3))
}
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)
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>()
}
}
In haskell you can do this:
type Parser a = String -> [(a, String)]
I tried to make something similar in Swift. So far I wrote these codes with no luck.
typealias Parser<A> = String -> [(A, String)]
typealias Parser a = String -> [(a, String)]
typealias Parser = String -> [(A, String)]
So is this simply impossible in swift? And if it is is there another ways to implement this behavior?
UPDATE: It seems generic typealiases are now supported in swift 3
https://github.com/apple/swift/blob/master/CHANGELOG.md
Generic typealias can be used since Swift 3.0. This should work for you:
typealias Parser<A> = (String) -> [(A, String)]
Here is the full documentation: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/typealias-declaration
Usage (from #Calin Drule comment):
func parse<A>(stringToParse: String, parser: Parser)
typealias cannot currently be used with generics. Your best option might be to wrap the parser function inside a struct.
struct Parser<A> {
let f: String -> [(A, String)]
}
You can then use the trailing closure syntax when creating a parser, e.g.
let parser = Parser<Character> { string in return [head(string), tail(string)] }
Generic Type Aliases - SE-0048
Status: Implemented (Swift 3)
The solution is straight-forward: allow type aliases to introduce type parameters, which are in scope for their definition. This allows one to express things like:
typealias StringDictionary<T> = Dictionary<String, T>
typealias IntFunction<T> = (T) -> Int
typealias MatchingTriple<T> = (T, T, T)
alias BackwardTriple<T1, T2, T3> = (T3, T2, T1)
Here I am presenting example for typealias that demonistrate you to how to use typealias in protocols definitions: I hope this helps you understand typealias
protocol NumaricType {
typealias elementType
func plus(lhs : elementType, _ rhs : elementType) -> elementType
func minus(lhs : elementType, _ rhs : elementType) -> elementType
}
struct Arthamatic :NumaricType {
func addMethod(element1 :Int, element2 :Int) -> Int {
return plus(element1, element2)
}
func minusMethod(ele1 :Int, ele2 :Int) -> Int {
return minus(ele1, ele2)
}
typealias elementType = Int
func plus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs + rhs
}
func minus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs - rhs
}
}
Output:
let obj = Arthamatic().addMethod(34, element2: 45) // 79