How do I write map that works for all types in Swift? - swift

As an exercise, I'm implementing a map function that takes an array and a function and applies the function to all elements of the array, but I don't know how to declare it such that it works for any type of array.
I can do something like
func intMap(var arr: [Int], fun: (Int) -> Int) -> [Int] {
for i in 0 ..< arr.count {
arr[i] = fun(arr[i])
}
return arr
}
intMap([1,2,3], {x in return x * x})
But this only works for int.
What is the type signature for Swift's built-in map?
Edit:
So I was missing the fact that I can declare param type signatures without declaring their types explicitly.
func myMap<T>(var arr: [T], fun: (T) -> T) -> [T] {
for i in 0 ..< arr.count {
arr[i] = fun(arr[i])
}
return arr
}
myMap([1,2,3], fun: {
x in return x * x
})

Create a new Playground
Just under where it has import UIKit type import Swift
Command click on the word Swift
This will open the Swift library and you can see all the type definitions there.
And you can see:
extension CollectionType {
/// Return an `Array` containing the results of mapping `transform`
/// over `self`.
///
/// - Complexity: O(N).
#warn_unused_result
#rethrows public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
Edited to add
Alternatively, you can write a more generalised map
func myMap<T, U>(var arr: [T], fun: T -> U) -> [U] {
var a: [U] = []
for i in 0 ..< arr.count {
a.append(fun(arr[i]))
}
return a
}
Which returns a new array, of a possibly different type, which you can see for yourself by putting this in your playground.
let a = [1, 2, 3]
let b = myMap(a, fun: { x in Double(x) * 2.1 })
a
b

Related

Using #discardableResult for Closures in Swift

Swift 3 has introduced the #discardableResult annotation for functions to disable the warnings for an unused function return value.
I'm looking for a way to silence this warning for closures.
Currently, my code looks like this:
func f(x: Int) -> Int -> Int {
func g(_ y: Int) -> Int {
doSomething(with: x, and: y)
return x*y
}
return g
}
In various places I call f once to obtain a closure g which I then call repeatedly:
let g = f(5)
g(3)
g(7)
g(11)
In most places I'm only interested in the side effects of the nested call to doSomething, and not in the return value of the closure g. With Swift 3, there are now dozens of warnings in my project for the unused result. Is there a way to suppress the warnings besides changing the calls to g to _ = g(...) everywhere? I couldn't find a place where I could place the #discardableResult annotation.
I don't think there's a way to apply that attribute to a closure. You could capture your closure in another that discards the result:
func discardingResult<T, U>(_ f: #escaping (T) -> U) -> (T) -> Void {
return { x in _ = f(x) }
}
let g = f(5)
g(3) // warns
let h = discardingResult(g)
h(4) // doesn't warn
I was looking for an answer to this recently, and I've found another way (a newer way) to do this!
It could arguably be overkill for some simple problems, but I just thought that this is an interesting yet neat approach that's worth sharing.
Say you have a closure that doubles an integer value:
let double = { (int: Int) -> Int in
return int * 2
}
With Swift 5.0 (SE-0216) introducing the #dynamicCallable attribute, you can "wrap" your closure with #discardableResult by creating a dynamically callable class or struct as such:
// same for struct, except without the need of an initializer
#dynamicCallable
class DiscardableResultClosure<T, U> {
var closure: (T) -> U
#discardableResult
func dynamicallyCall(withArguments args: [Any]) -> U {
let arg = args.first as! T
return self.closure(arg)
}
// implicit for struct
init(closure: #escaping (T) -> U) {
self.closure = closure
}
}
double(5) // warning: result of call to function returning 'Int' is unused
let discardableDouble = DiscardableResultClosure(closure: double)
discardableDouble(5) // * no warning *
Even better, in Swift 5.2 (SE-0253), you can create a dynamically callable struct using a built-in callAsFunction method without going through the trouble of using the attribute #dynamicCallable (or using class) with its sometimes cumbersome declaration.
struct DiscardableResultClosure<T, U> {
var closure: (T) -> U
#discardableResult
func callAsFunction(_ arg: T) -> U {
return closure(arg)
}
}
let discardableDouble = DiscardableResultClosure(closure: double)
discardableDouble(5) // * no warning *

How do I make a generic function for addable parameters?

Working with Swift generics, I have the following question:
This function works as expected with the type Int:
func + (number: Int, vector: [Int]) -> [Int] {
var resArray:[Int]=[]
for x:Int in vector {
resArray.append(number+x)
}
return resArray
}
I want to make it work with any type where addition makes sense.
I have tried the following:
func +<T:NSNumber> (number: T.Type, vector: [T.Type]) -> [T.Type] {
var resArray:[T.Type]=[]
for x:T.Type in vector {
resArray.append(number+x)
}
return resArray
}
But the line:
resArray.append(number+x)
hits a problem because number and x should obvious support addition.
How should I change my code? I suppose I need to add a constraint on the type. I don't quite know how.
You can define such a constraint as you said, as a protocol like AdditiveSemigroup below.
protocol AdditiveSemigroup {
typealias Out = Self
static func + (a: Self, b: Self) -> Out
}
func +<T: AdditiveSemigroup where T.Out == T> (value: T, vector: [T]) -> [T] {
return vector.map { $0 + value }
}
To make a type conform the protocol above, just define extension on that type.
extension String: AdditiveSemigroup {}
"A" + ["A", "B", "C"] // ==> ["AA", "AB", "AC"]
For the NSNumber, there've been no built-in + operatator, so you have to define it by hand.
extension NSNumber: AdditiveSemigroup {
typealias This = NSNumber
}
func + (a: NSNumber, b: NSNumber) -> NSNumber {
return NSNumber(double: a.doubleValue + b.doubleValue)
}
Now you could apply your special + operator to values of NSNumber.
NSNumber(double: 3) + [NSNumber(double: 5)] // ==> 8

Efficiently aggregating an array of non-optionals without a default value

I need to efficiently aggregate an array of non-optional values, knowing its size, having a way to get its values, but not having a default value.
Following is a rather synthetic example, resembling what I need. It won't compile, but it will give you the idea:
public func array<A>( count: Int, getValue: () -> A ) -> Array<A> {
var array = [A](count: count, repeatedValue: nil as! A)
var i = 0
while (i < count) {
array[i] = getValue()
i++
}
return array
}
Please note that the result of type Array<A?> won't do, I need non-optionals. Also note that the solution must be efficient, it must not do any extra traversals.
You can make a working function from your example code by using
the append() method to add array elements:
public func array<A>(count: Int, #noescape getValue: () -> A) -> [A] {
var array = [A]()
array.reserveCapacity(count)
for _ in 0 ..< count {
array.append(getValue())
}
return array
}
The #noescape
attribute tells the compiler that the passed closure does not outlive
the function call, this allows some performance optimizations,
compare #noescape attribute in Swift 1.2.
But it is easier to use the map() method of CollectionType:
/// Return an `Array` containing the results of mapping `transform`
/// over `self`.
///
/// - Complexity: O(N).
#warn_unused_result
public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
In your case:
public func array<A>(count: Int, #noescape getValue: () -> A) -> [A] {
let array = (0 ..< count).map { _ in getValue() }
return array
}
Here map() transforms each integer in the range 0 ... count-1
to an array element. The underscore in the closure indicates that
its argument (the current index) is not used.
I leave it to you to check which method is faster.
Example usage:
let a = array(10) { arc4random_uniform(10) }
print(a) // [3, 7, 9, 4, 2, 3, 1, 5, 9, 7] (Your output may be different :-)

Using Array.map instead of array.map

Here is what I can do in Swift:
extension Int {
func square() -> Int { return self * self }
}
And then call it like this: 3.square(), that gives me 9. Also, i can do it like so: Int.square(3), and it will give me () -> (Int). So, Int.square(3)() gives 9.
But if I write let array = [1, 2, 3]; Array.map(array) it gives error Cannot convert value of type 'Array<Int>' to expected argument of type '[_]'
Question is, how I can use Array.map in that way?
EDIT
Ok, I'll try to explain my problem in details. Now, I have function like this:
func map<T, U>(f: T -> U) -> [T] -> [U] {
return { ts in
ts.map(f)
}
}
It works, but only on arrays. There are many types that have map function, and it not very nice to declare global function like that for every type. So, lets say there is type C that have map function C<T> -> (T -> U) -> C<U>
Also, lets say I have function f, that transform A -> B -> C into B -> A -> C.
So, it looks like I can do something like this:
let array = [1, 2, 3]
let square: Int -> Int = {$0 * $0}
map(square)(array) // [1, 4, 9], works fine
f(Array.map)(square)(array) // Error
Question is not about code readability but about how Swift's type system works.
Array.map function is defined as:
public func map<T>(self: [Self.Generator.Element]) -> (#noescape Self.Generator.Element throws -> T) rethrows -> [T]
The problem here is that the compiler cannot infer the return type of the transform function or T. So you have to define it the two following ways:
// variable declaration
let mapping: (Int -> Int) throws -> [Int] = Array.map(array)
// or (especially useful for further function calls)
aFunction(Array.map(array) as (Int -> Int) throws -> [Int])
You can also see that the map function is marked as rethrows which gets "translated" to throws if you use the function. (It looks like a bug but closures don't have rethrows which could be the reason for this behavior).
So the function f could look like this in order to use it with Array.map:
// where
// A is the array
// B is the function
// C the type of the returned array
func f<A, B, C>(f2: A -> (B throws -> C)) -> B -> (A throws -> C) {
return { b in
{ a in
try f2(a)(b)
}
}
}
// or with a forced try! so you don't have to use try
func f<A, B, C>(f2: A -> (B throws -> C)) -> B -> A -> C {
return { b in
{ a in
try! f2(a)(b)
}
}
}
// call f (use try if you use the first implementation)
let square: Int -> Int = {$0 * $0}
f(Array.map)(square)
In the example with square the compiler can infer the type of the expression. In other words:
let f = Int.square(3)
is the same as
let f:() -> Int = Int.square(3)
However, map is a generic function that is parameterized on the closure return type:
public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
Consequently, this generates an error because the compiler doesn't know what T is:
let f = Array<Int>.map([1, 2, 3])
However, you can explicitly tell it what T is like this:
let f: ((Int) throws -> Int) throws -> [Int] = Array.map([1, 2, 3])
try! f({$0 * $0})
I think that answers your first question about square and map. I don't completely understand the rest of your question about converting A -> B -> C to B -> A -> C. Maybe you can provide more info on what f would look like.

Im confused on how this function is being called, there is no call for it?

I'm confused on how getFunctionNeededForReference is running. There is no call for it and where are the functions returned to? where are they going? I know they are being referenced but where are the functions going to, there is not call for getFunctionNeededForReference in the beginning? there is no call sending the argument flag anyway?
func add ( a: Int , b : Int)-> Int {
//returing a result and not a variable
return a + b
}
func multiply ( a: Int, b: Int) -> Int{
return a * b
}
// declaring a function as a variable, it takes in 2 Ints and returns an Int
var f1 : (Int, Int)-> Int
f1 = add
f1 = multiply
// Function as a parameter
func arrayOperation (f: (Int, Int) -> Int , arr1: [Int] , arr2: [Int]) -> [Int]
{
// Declaring and initializing an empty array to return
var returningArray = [Int]()
for (i, val) in enumerate(arr1)
{
returningArray.append(f(arr1 [i], arr2 [i]))
}
return returningArray
}
arrayOperation(add, [2,3,4], [4,5,6])
arrayOperation(multiply, [2,3,4], [4,5,6])
//Function as a return value
func getFunctionNeededForReference (flag : Int) -> (Int,Int) ->Int
{
if flag == 0 {
return add
}else {
return multiply
}
}
What you've posted is just some example code showing things that Swift supports. It's not code that's useful for anything. It's just demonstrating Swift's syntax for first-class functions.
If you don't understand what “first-class functions” means, you can look up the term in your favorite search engine and find many explanations.