I've read this post, but need a little additional help.
I would like to construct a Closure which takes in a variable amount of Doubles, compares them to a threshold (which is also a Double) and returns a Bool checking if ALL entries were greater than the threshold. The return type should be (Double...) -> Bool
Here is what I have so far:
func isAllAbove(lower: Double) -> (Double...) -> Bool {
return {
var conditions: [Bool] = []
for i in 0...$0.count {
conditions.append(lower < $0[i])
}
return !conditions.contains(false)
}
}
However, the compiler complains that
Cannot convert return expression of type '(_) -> _' to return type '(Double...) -> Bool'
Why is this happening and how can I fix this? Thanks!
Try to specify parameter type and return type in closure to helps compiler to understand what value it should take and return. Also, you have a mistake in for loop. The interval should be like this 0 ..< values.count:
func isAllAbove(lower: Double) -> (Double...) -> Bool {
return { (values: Double...) -> Bool in
var conditions: [Bool] = []
for i in 0 ..< values.count {
conditions.append(lower < values[i])
}
return !conditions.contains(false)
}
}
let allAbove = isAllAbove(lower: 2)
print(allAbove(1, 2, 3)) // false
Also, you can write it almost in 1 line of code:
let lower = 2
let isAllAbove = ![1, 2, 3].contains { $0 < lower }
print(isAllAbove1) // false
Related
This is the sample code from swift documentation. I am learning swift language, and I saw the functiontype as parameter, The sample code does not have inout keyword. But I am trying to use this with inout paramter, but the below sample is not working as expected.
https://docs.swift.org/swift-book/LanguageGuide/Functions.html (Function Types as Return Types)
//Function Types as Return Types
func stepForward(_ input: inout Int) -> Int {
return input + 1
}
func stepBackward(_ input: inout Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (inout Int) -> Int {
let a = backward ? stepBackward : stepForward
return a
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
print(moveNearerToZero(¤tValue))
print(currentValue)
Actual output
2
3
Expected output
2
2
Because CurrentValue is inout paramter. Passing the currentValue as 3 initially prints value 2 using stepBackward() method
and I want to maintain the value after the decrement.
But the currentValue is not maintained here.
That's because you are not actually assigning value to parameter after applying arithmetics you are just returning new value without assigning it. Try the following code
//Function Types as Return Types
func stepForward(_ input: inout Int) -> Int {
input += 1
return input
}
func stepBackward(_ input: inout Int) -> Int {
input -= 1
return input
}
func chooseStepFunction(backward: Bool) -> (inout Int) -> Int {
let a = backward ? stepBackward : stepForward
return a
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
print(moveNearerToZero(¤tValue))
print(currentValue)
You can try it without return anything. Just pass current value in function and update the value it will automatically update current value.
func stepForward(_ input: inout Int) {
input = input + 1
}
func stepBackward(_ input: inout Int) {
input = input - 1
}
func chooseStepFunction(backward: Bool, currentValue: inout Int) {
backward ? stepBackward(¤tValue) : stepForward(¤tValue)
}
var currentValue = 3
chooseStepFunction(backward: currentValue > 0, currentValue: ¤tValue)
print(currentValue)
your problem is that you never changed the currentValue value !
you should change the currentValue value in chooseStepFuction method !
chooseStepFunction(backward: currentValue > 0,
currentValue: ¤tValue)
Is there a more elegant way to filter with an additional parameter (or map, reduce).
When I filter with a single parameter, we get a beautiful easy to ready syntax
let numbers = Array(1...10)
func isGreaterThan5(number:Int) -> Bool {
return number > 5
}
numbers.filter(isGreaterThan5)
However, if I need to pass an additional parameter to my function it turns out ugly
func isGreaterThanX(number:Int,x:Int) -> Bool {
return number > x
}
numbers.filter { (number) -> Bool in
isGreaterThanX(number: number, x: 8)
}
I would like to use something like
numbers.filter(isGreaterThanX(number: $0, x: 3))
but this gives a compile error annonymous closure argument not contained in a closure
You could change your function to return a closure which serves
as predicate for the filter method:
func isGreaterThan(_ lowerBound: Int) -> (Int) -> Bool {
return { $0 > lowerBound }
}
let filtered = numbers.filter(isGreaterThan(5))
isGreaterThan is a function taking an Int argument and returning
a closure of type (Int) -> Bool. The returned closure "captures"
the value of the given lower bound.
If you make the function generic then it can be used with
other comparable types as well:
func isGreaterThan<T: Comparable>(_ lowerBound: T) -> (T) -> Bool {
return { $0 > lowerBound }
}
print(["D", "C", "B", "A"].filter(isGreaterThan("B")))
In this particular case however, a literal closure is also easy to read:
let filtered = numbers.filter( { $0 > 5 })
And just for the sake of completeness: Using the fact that
Instance Methods are Curried Functions in Swift, this would work as well:
extension Comparable {
func greaterThanFilter(value: Self) -> Bool {
return value > self
}
}
let filtered = numbers.filter(5.greaterThanFilter)
but the "reversed logic" might be confusing.
Remark: In earlier Swift versions you could use a curried function
syntax:
func isGreaterThan(lowerBound: Int)(value: Int) -> Bool {
return value > lowerBound
}
but this feature has been removed in Swift 3.
The following function finds the second index of a given item in Array of Int:
func secondIndexOf(item: Int, inArray array: Array<Int>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<Int> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}
However, when I attempt to create a generic version of this function to find the second Equatable item, I get an error:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> T? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item) // Cannot invoke 'indexOf' with an argument list of type '(T)'
}
return nil
}
Why is this not valid Swift code, and what is the expected argument list if not (T)? Xcode autocomplete shows indexOf(element: Comparable) with which T should be compatible.
The compiler is giving you a confusing error message here—it isn't actually concerned about the argument. The return value is the source of the problem, since you aren't returning a value of type T, but an index of the array. You just need to change your return type to Int?:
func secondIndexOf<T: Equatable>(item: T, inArray array: Array<T>) -> Int? {
if let firstIndex: Int = array.indexOf(item) {
let slice: ArraySlice<T> = array.suffixFrom(firstIndex + 1)
return slice.indexOf(item)
}
return nil
}
Both map and flatMap are defind on ImplicitlyUnwrappedOptional, but they differ (obviously) in their definition according to the documentation:
func map(f: #noescape (T) -> U) -> U!
If self == nil, returns nil. Otherwise, returns f(self!).
func flatMap(f: #noescape (T) -> U!) -> U!
Returns f(self)! iff self and f(self) are not nil.
I tried using them with a simple example:
let number: Int? = 1
let res1 = number.map { $0 + 1 }.map { $0 + 1 }
let res2 = number.flatMap { $0 + 1 }.flatMap { $0 + 1 }
res1 //3
res2 //3
But they produced the same results even if number was nil.
So my question is, what is the actual difference between them if I apply map or flatMap to ImplicitlyUnwrappedOptionals? Which one should I choose over the other and when?
(Remark: The answer has been updated to reflect the syntax changes in Swift 3 and later, such as the abolishment of ImplicitlyUnwrappedOptional.)
Optional.map() and Optional.flatMap() are declared as follows (I have omitted the throws/rethrows modifiers which are irrelevant here):
func map<U>(_ transform: (Wrapped) -> U) -> U?
func flatMap<U>(_ transform: (Wrapped) -> U?) -> U?
Let's consider a simplified version of your first example using “map”:
let number: Int? = 1
let res1 = number.map { $0 + 1 }
print(res1) // Optional(2)
number has the type Int? and the closure type is inferred as (Int) -> Int. U is Int, and the type of the return value is Int?. number is not nil, so it is unwrapped and passed 1 is passed to the closure. The closure returns 2 and map returns Optional(2). If number were nil then the result would be nil.
Now we consider a simplified version of your second example with “flatMap”:
let number: Int? = 1
let res2 = number.flatMap { $0 + 1 }
print(res2) // Optional(2)
flatMap expects a closure of type (Wrapped) -> U?, but { $0 + 1 } does not return an optional. In order to make it compile, the compiler converts this to
let res2 = number.flatMap { return Optional($0 + 1) }
Now the closure has type (Int) -> Int?, and U is Int again. Again, number is unwrapped and passed to the closure. The closure returns Optional(2) which is also the return value from flatMap. If number were nil or if the closure would return nil then the result would be nil.
So there is indeed no difference between these invocations:
let res1 = number.map { $0 + 1 }
let res2 = number.flatMap { $0 + 1 }
However that is not what flatMap is meant for. A more realistic example would be
func foo(_ s : String?) -> Int? {
return s.flatMap { Int($0) }
}
print(foo("1")) // Optional(1)
print(foo("x")) // nil (because `Int($0)` returns nil)
print(foo(nil)) // nil (because the argument is nil)
Generally, map takes a closure of type (Wrapped) -> U and transforms
Optional<Wrapped>.none --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> Optional<U>.some(transform(wrapped))
flatMap takes a closure of type (Wrapped) -> U? and transforms
Optional<Wrapped>.none --> Optional<U>.none
Optional<Wrapped>.some(wrapped) --> transform(wrapped)
Here transform(wrapped) can be Optional<U>.none as well.
If (as in your example) flatMap is called with a closure which does not return an optional then the compiler converts it to an optional automatically, and there is no difference to map anymore.
This is not possible with map() where the mapping closure has the signature (T) -> U.
That's not quite right. In my view, Martin R's answer doesn't quite get at the heart of the problem, which is that the docs do not correctly describe the difference between map and flatMap.
The difference is not what kind of closure they take. Each will happily accept a closure that produces a nonOptional or a closure that produces an Optional — despite what the docs say, and despite the difference in their declarations. All of these expressions compile:
let i : Int? = nil
let result1 = i.map {_ in "hello"} // map, closure produces nonOptional
let result2 = i.flatMap {_ in "hello"} // flatMap, closure produces nonOptional
let result3 = i.map {_ in Optional("hello") } // map, closure produces Optional
let result4 = i.flatMap {_ in Optional("hello") } // flatMap, closure produces Optional
Okay, so what's the actual difference? It's what flatMap does just in case the closure does produce an Optional: it unwraps it, thus preventing a double-wrapped Optional:
let i : Int? = nil
let result1 = i.map {_ in "hello"} // String?
let result2 = i.flatMap {_ in "hello"} // String?
let result3 = i.map {_ in Optional("hello") } // String?? // double-wrapped
let result4 = i.flatMap {_ in Optional("hello") } // String? // not double-wrapped
That is the only difference between map and flatMap.
flatMap resolves nested optionals whereas map does not.
flatmap
var temp: Int? = 3
var flag: Bool = false
print(temp.flatMap { $0 < 5 ? 1 : nil } ?? .zero)
// output: 1
map
var temp: Int? = 3
var flag: Bool = false
print(temp.map { $0 < 5 ? 1 : nil } ?? .zero)
// output: Optional(Optional(1))
[map vs compactMap vs flatMap]
Swift Optional map vs flatMap
Let's create our own simple realisation of Optional type and implement map and flatMap functions
enum CustomOptional<T> {
case none
case some(T)
public init(_ some: T) {
self = .some(some)
}
func map<U>(_ transform: (T) -> U) -> CustomOptional<U> {
switch self {
case .some(let value):
let transformResult: U = transform(value)
let result: CustomOptional<U> = CustomOptional<U>(transformResult) //<-- force wrap the transformResult
return result
case .none:
return .none
}
}
func flatMap<U>(_ transform: (T) -> CustomOptional<U>) -> CustomOptional<U> {
switch self {
case .some(let value):
let transformResult: CustomOptional<U> = transform(value)
let result: CustomOptional<U> = transformResult
return result
case .none:
return .none
}
}
}
map - can return Optional Optional
flatMap - can flat Optional Optional to Optional
Optional.map { () -> T } -> Optional<T>
Optional.map { () -> Optional<T> } -> Optional<Optional<T>>
Optional.flatMap { () -> Optional<T> } -> Optional<T>
map: returned value of transformed function is wrapped into Optional of returned value of map function
flatMap: returned value of transformed function is the same as returned value of flatMap function
//problem
//T == Int, U == CustomOptional<String>
//map<U>(_ transform: (T) -> U) -> CustomOptional<U>
//map<CustomOptional<String>>(_ transform: (Int) -> CustomOptional<String>) -> CustomOptional<CustomOptional<String>>
let result: CustomOptional<CustomOptional<String>> = CustomOptional(1).map { int in
return CustomOptional("Hello: \(int)")
}
//solution
//T == Int, U == String
//flatMap<U>(_ transform: (T) -> CustomOptional<U>) -> CustomOptional<U>
//flatMap<U>(_ transform: (Int) -> CustomOptional<String>) -> CustomOptional<String>
let result5: CustomOptional<String> = CustomOptional(1).flatMap { int in
return CustomOptional("Hello: \(int)")
}
[Swift Functor, Applicative, Monad]
I'm trying to do create some closure definitions which I'm gonna use a lot in my iOS app. So I thought to use a typealias as it seemed the most promising ...
I did a small Playground example which shows my issue in detail
// Here are two tries for the Closure I need
typealias AnonymousCheck = (Int) -> Bool
typealias NamedCheck = (number: Int) -> Bool
// This works fine
var var1: AnonymousCheck = {
return $0 > 0
}
var1(-2)
var1(3343)
// This works fine
var var2: NamedCheck = {
return $0 > 0
}
var2(number: -2)
var2(number: 12)
// But I want to use the typealias mainly as function parameter!
// So:
// Use typealias as function parameter
func NamedFunction(closure: NamedCheck) {
closure(number: 3)
}
func AnonymousFunction(closure: AnonymousCheck) {
closure(3)
}
// This works as well
// But why write again the typealias declaration?
AnonymousFunction({(another: Int) -> Bool in return another < 0})
NamedFunction({(another: Int) -> Bool in return another < 0})
// This is what I want... which doesn't work
// ERROR: Use of unresolved identifier 'number'
NamedFunction({NamedCheck in return number < 0})
// Not even these work
// ERROR for both: Anonymous closure arguments cannot be used inside a closure that has exlicit arguments
NamedFunction({NamedCheck in return $0 < 0})
AnonymousFunction({AnonymousCheck in return $0 < 0})
Am I missing something or is it just not supported in Swift?
Thanks
EDIT/ADDITION:
The above is just a simple example. In real life my typealias is more complicated. Something like:
typealias RealLifeClosure = (number: Int, factor: NSDecimalNumber!, key: String, upperCase: Bool) -> NSAttributedString
I basically want to use a typealias as a shortcut so I don't have to type that much. Maybe typealias isn't the right choice... Is there another?
You aren't rewriting the typealias declaration in this code, you're declaring the parameters and return type:
AnonymousFunction({(another: Int) -> Bool in return another < 0})
Happily, Swift's type inference lets you use any of the following - pick the style that feels best to you:
AnonymousFunction( { (number: Int) -> Bool in number < 0 } )
AnonymousFunction { (number: Int) -> Bool in number < 0 }
AnonymousFunction { (number) -> Bool in number < 0 }
AnonymousFunction { number -> Bool in number < 0 }
AnonymousFunction { number in number < 0 }
AnonymousFunction { $0 < 0 }
I don't think you'll be able to do what you want. To simplify your example slightly, you can do this:
typealias NamedCheck = (number: Int) -> Bool
let f: NamedCheck = { $0 < 5 }
f(number: 1)
NamedFunction(f)
NamedFunction( { $0 < 5 } as NamedCheck)
But you can't do what you want, which is to rely on the fact that the tuple arg is called number to refer to it inside the closure without giving it as part of the closure:
// compiler error, no idea what "number" is
let g: NamedCheck = { number < 5 }
Bear in mind that you can name the parameter without giving it a type (which is inferred from the type of g):
let g: NamedCheck = { number in number < 5 }
but also, you can name it whatever you want:
let h: NamedCheck = { whatevs in whatevs < 5 }
NamedFunction(h)
Here's what I think is happening (this is partly guesswork). Remember how functions can have external and internal argument names:
func takesNamedArgument(#namedArg: Int) { etc... }
Or, to write it longhand:
func takesNamedArgument(namedArg namedArg: Int) { etc... }
But you can also give as the second, internal, name whatever you like:
func takesNamedArgument(namedArg whatevs: Int) { etc... }
I think this is what is happening with the closures with named tuples. The "external" name is "number", but you must give it an "internal" name too, which is what you must use in the function body. You can't make use of the external argument within your function. In case of closure expressions, if you don't give an internal name, you can use $0 etc, but you can't just skip it, any more than you can skip the internal name altogether and just rely on the external name when defining a regular function.
I was hoping that I could prove this theory by the following:
let f = { (#a: Int, #b: Int)->Bool in a < b }
resulting in f being of type (a: Int, b: Int)->Bool). This compiles, as does:
let g = { (number1 a: Int, number2 b: Int)->Bool in a < b }
but it doesn't look like the external names for the argument make it out to the type of f or g.
The syntax to create a closure is:
{ (parameters) -> return type in
statements
}
What's at the left of in is the closure signature (parameters and return value). In some cases the signature can be omitted or simplified when type inference is able to determine the number of parameters and their type, and the return value.
In your case it doesn't work because you are passing a type alias, but it is interpreted as a parameter name. The 3 lines work if either you:
name the parameter properly
NamedFunction({number in return number < 0})
AnonymousFunction({number in return number < 0})
use shorthand arguments:
NamedFunction({ return $0 < 0})
AnonymousFunction({ return $0 < 0})
use shorthand arguments and implicit return:
NamedFunction({ $0 < 0})
AnonymousFunction({ $0 < 0})