Code:
var treasures: [Treasure] = []
treasures = [treasureA, treasureB, treasureC, treasureD, treasureE]
let rectToDisplay = self.treasures.reduce(MKMapRectNull) {
(mapRect: MKMapRect, treasure: Treasure) -> MKMapRect in
// 2
let treasurePointRect = MKMapRect(origin: treasure.location.mapPoint, size: MKMapSize(width: 0, height: 0))
// 3
return MKMapRectUnion(mapRect, treasurePointRect)
}
In the code above, we are running the reduce function on treasures array, two parameters are passed in the closure: (mapRect: MKMapRect, treasure: Treasure). How does the closure know to that the second parameter will be the element from the treasures array and the first parameter will be result of the what this closure returns?
Is this something by default that the second parameter passed in the closure will be the element from the array that's executing the reduce function?
Swift's array class has a definition of reduce that most likely looks something like this:
func reduce<T>(initial: T, fn: (T, T) -> T) -> T {
var val = initial
for e in self {
val = fn(val, e)
}
return e
}
That is to say, the definition of reduce dictates the order in which parameters are passed to the closure you provide.
Note that the actual definition of Swift's reduce is more complicated than the one I provided above, but the example above is the basic gist.
If you look at the definition of reduce:
func reduce<S : SequenceType, U>(sequence: S, initial: U, combine: #noescape (U, S.Generator.Element) -> U) -> U
The first parameter of the closure is the result and the second is element of your sequence.
Related
extension Array {
func reduce<T>(_ initial: T, combine: (T, Element) -> T) -> T {
var result = initial
for x in self {
result = combine(result, x)
}
return result
}
}
How does the below function work when it only passes a * to the combine closure?
func productUsingReduce(integers: [Int]) -> Int {
return integers.reduce(1, combine: *)
}
static func * (lhs: Self, rhs: Self) -> Self is an operator function defined on the Numeric protocol. So, you are really just passing in a function that takes two arguments.
What does the declaration mean?
combine: (T, Element) -> T
It says: the combine parameter is a function that takes two parameters, a T and an Element, and returns a T.
Well, in Swift, operators are functions, and * is such a function. So it suffices to pass a reference to this function as the combine parameter. The bare name, *, is that reference.
Suppose I have an array of closures which can all be composed with one another (i.e., endomorphisms, their input and output types are the same). How can I compose these closures into a single closure?
For reference, I was trying to design something like the following.
struct MyType {
typealias MyClosure: (T) -> T
private var myClosures: [MyClosure] = [ ... ]
public var closure: MyClosure {
get {
return ? // somehow compose all of myClosures into a single closure here
}
}
}
My first thought was to use reduce, à la myClosures.reduce(STARTING) { a, b in b(a) },
but this requires a starting value to be supplied, and then successively applies the closures to it. I don't want to apply the closures to anything (yet), but just synthesize the private list of closures into a single, public closure which can be applied later. Given the way reduce is
defined, I expect this would look something like
myClosures.reduce(identity) { a, b in compose(a, b) }
func identity(_ input: T) { return input }
func compose(a: MyClosure, b: MyClosure) -> MyClosure { return b(a) }
but the type of b(a) is T, not (T) -> T. How can this be accomplished? Is this a better way of going about closure composition?
Edit: My original answer misunderstood what your problem was. But seeing as my original answer might be useful to future readers, I'll leave it at the bottom.
Your compose function is nearly there! b(a) does not compile because MyClosure does not take another MyClosure. b(a) is invoking the closure ("function application"). not composition. Since compose returns a closure, why not return a closure? A typical closure looks like this in Swift:
{ (param) in return doSomethingTo(param) }
So let's return that!
return { (x) in return b(a(x)) }
This can be simplified to:
{ b(a($0)) } // "return" can be omitted as well!
This page (among other things) tells you how and when you can simplify closure syntaxes.
Original answer:
Using reduce is the correct choice here. The reduction operation is composition, so let's write a compose function first:
func compose<T>(_ x: #escaping (T) -> T, _ y: #escaping (T) -> T) -> (T) -> T {
{ y(x($0)) } // or { x(y($0)) } if you want it the other way
}
Then, we reduce. What's the identity? The identity is something that has these properties:
compose(identity, anything) == anything
compose(anything, identity) == anything
What function does that? The identity function!
So we get:
func reduceClosures<T>(_ closures: [(T) -> T]) -> (T) -> T {
closures.reduce({ $0 }, compose)
}
Recently I have encountered a need of creating an Array of Functions. Unfortunately, Swift language does not provide a top level type for functions, but instead they must be declared by their specific signature (...)->(...). So I tried to write a wrapper that can hold any function and later specialize it to hold only closures having Void return type and any number of arguments.
struct AnyFunction {
let function: Any
init?(_ object: Any){
switch String(describing: object){
case let function where function == "(Function)":
self.function = object
default:
return nil
}
}
func callAsFunction(){
self.function()
}
}
As I was progressing, I have found out that it is not trivial and possibly requires some hacks with introspection, but I failed to find solution, despite of my attempt. The Compiler messaged:
error: cannot call value of non-function type 'Any'
So how would you make this trick that is, to clarify, to define an Object that can hold any functional type?
Clarification:
What I would prefer is defining something like:
typealias SelfSufficientClosure = (...)->Void
var a, b, c = 0
let funcs = FunctionSequence
.init(with: {print("Hi!")}, {a in a + 3}, {b in b + 3}, { a,b in c = a + b})
for f in funcs { f() }
print([a, b, c])
//outputs
//"Hi"
//3, 3, 6
PS This question has relation to this one (Any or a trouble with sequence of functions)
A function is a mapping from inputs to outputs. In your examples, your inputs are void (no inputs), and your outputs are also void (no outputs). So that kind of function is precisely () -> Void.
We can tell that's the right type because of how you call it:
for f in funcs { f() }
You expect f to be a function that takes no inputs and returns no outputs, which is exactly the definition of () -> Void. We can get exactly the input and output you expect by using that type (and cleaning up a few syntax errors):
var a = 0, b = 0, c = 0
let funcs: [() -> Void] = [{print("Hi!")}, {a = a + 3}, { b = b + 3}, { c = a + b}]
for f in funcs { f() }
print(a, b, c, separator: ",")
//outputs
//Hi!
//3, 3, 6
When you write a closure like {a in a + 3}, that doesn't mean "capture a" (which I believe you are expecting). It means "This is a closure that accepts a parameter that will be called a (completely unrelated to the global variable of the same name) and returns that value plus 3." If that's what you meant, then when you called f(), you would need to pass it something and do something with the return value.
You can use an enum to put various functions into the Array and then extract the functions with a switch.
enum MyFuncs {
case Arity0 ( Void -> Void )
case Arity2 ( (Int, String) -> Void)
}
func someFunc(n:Int, S:String) { }
func boringFunc() {}
var funcs = Array<MyFuncs>()
funcs.append(MyFuncs.Arity0(boringFunc))
funcs.append( MyFuncs.Arity2(someFunc))
for f in funcs {
switch f {
case let .Arity0(f):
f() // call the function with no arguments
case let .Arity2(f):
f(2,"fred") // call the function with two args
}
}
Given:
class Elem {
func f() -> AnotherElem {
return AnotherElem(elem: self)
}
}
I want to call the map function on array of Elems passing the function f:
Sample code:
collection.map { $0.f() }
However, I don't like this {} notation so I was thinking whether or not I can pass a function as an argument (which in my eyes increases readability), and indeed I can
What I want is to do the following:
collection.map(Elem.f)
The last is valid syntax however the type of the array is the following: [() -> AnotherElem] instead of expected [AnotherElem] type.
Is a bug or a feature?
Obviously, this could be solved by calling map again and calling the array of blocks, but this is not the problem I'm having.
I'm struggling to understand why it is the way it is
This is expected behaviour, i.e. not a bug.
If you try to use an instance method someMethod of the form(T) -> U directly like this:
SomeType.someMethod
The type of that expression is (SomeType) -> (T) -> U. In your case, The type of Elem.f is (Elem) -> () -> AnotherElem.
Why is it designed like this? It is so that you can pass an instance to SomeType.someMethod, and then get the original instance method:
let f = SomeType.someMethod(instanceOfSomeType)
I guess this could be somewhat called "currying".
Anyway, you would need another function to transform Elem.f:
func uncurry<T, U>(_ f: #escaping (T) -> () -> U) -> (T) -> U {
return { f($0)() }
}
Now passing uncurry(Elem.f) will work.
I'm working through understanding the parameters used in the (simple) version of the memoized fibonacci explained in the Advanced Swift session (jump to 00:38:00)
In the session the following memoize function is defined (adapted to Swift 3)
func memoize<T: Hashable, U>(body: #escaping (T) -> U) -> (T) -> U {
var memo = Dictionary<T, U>()
return { x in
if let q = memo[x] { return q }
let r = body(x)
memo[x] = r
return r
}
}
And it will wrap simple functions, for example:
let ntos = memoize {(n: Int) -> String in
print("Must evaluate something")
return "\(n)"
}
print(ntos(3))
print(ntos(3))
print(ntos(30))
output:
Must evaluate something
3
3
Must evaluate something
30
The type of ntos is (Int) -> String so the T in memoize becomes Int and U becomes String.
But for the fibonacci function, the example apple are using is
let fibonacci = memoize {
fibonacci, n in
n < 2 ? Double(n) : fibonacci(n: n - 1) + fibonacci(n: n - 2)
}
Here I'm not sure what types T, and U are adapting? and how the function behaves for the recursive nature? How the closure parameter declaration fibonacci, n translate to the type memoize (T) -> U body parameter?
Why fibonacci is even in the definition of closure passed to memoize? I assume it's something to do with the idea of curried functions (that was replaced by closures in Swift 3) but the implementation syntax just doesn't clicks for me.
I've decided to it a step further and wrote a full fledges walk through of memoize