Use Logical Operator as Combine Closure in Reduce

Guard condition provokes compiler error that talks about closure

The problem, as explained by Martin in this Q&A, is that the || operator is implemented with an @autoclosure second parameter, in order to allow for short-circuit evaluation (the right hand expression need only be evaluated if the left hand expression evaluates to false).

Therefore in the expression

b == nil || self.a > 0

self.a > 0 is implicitly wrapped in a () -> Bool closure. This is problematic, because it requires the capture of self, so that a can be accessed upon applying the closure.

However, in an initialiser, Swift tightly restricts what you can do with self before it has been fully initialised. One of these restrictions is the inability to be captured by a closure – which is why you get a compiler error.

Although really, there's nothing wrong with the closure { self.a > 0 } capturing self before it's fully initialised, because all the closure is doing is accessing a on it, which has already been initialised. Therefore, this is really just an edge case (for which there's an open bug report), which I hope will be smoothed out in a future version of the language.

Until then, one solution as shown by Martin in this Q&A, is to use a temporary local variable to create a copy of the value of self.a, avoiding the capturing of self in the closure:

class Foo {
var a: Int
var b: Int

init(a: Int, b: String?) throws {

// some computation meaning that a != self.a
self.a = a * 42

// temporary local variable to be captured by the @autoclosure.
let _a = self.a
guard b == nil || _a > 0 else {
throw "Too little a!"
}

self.b = self.a
}
}

extension String: Error {}

Obviously, this assumes that self.a != a, otherwise you can just refer to a instead of self.a in the guard condition.

What is the type of the logical operators?

If you "cmd-click" on the word "Swift" in the statement

import Swift

in Xcode and search for || then you'll find that it is declared as

func ||<T : BooleanType>(lhs: T, rhs: @autoclosure () -> Bool) -> Bool

The reason is the "short-circuiting" behaviour of the || operator: If the first
operand is true, then the second operand must not be evaluated at all.

So you have to declare the parameter as

combine: (Bool, @autoclosure () -> Bool) -> Bool

Example:

func combineWith(a : Bool, b : Bool, combine: (Bool, @autoclosure () -> Bool) -> Bool) -> Bool {
return combine(a, b)
}

let result = combineWith(false, true, ||)
println(result)

Note: I tested this with Xcode 6.1.1. The syntax for autoclosure
parameters changed in Swift 1.2 (Xcode 6.3) and I haven't been able yet
to translate the above code for Swift 1.2 (see also Rob's comments
below).

The only thing that I can offer at the moment are extremely ugly
workarounds. You could wrap || into a closure that does not have
autoclosure parameters:

func combineWith(a : Bool, b : Bool, combine: (Bool, () -> Bool) -> Bool) -> Bool {
return combine(a, { b })
}

let result = combineWith(false, true, { $0 || $1() } )

Or you go without the short-circuiting behaviour:

func combineWith(a : Bool, b : Bool, combine: (Bool, Bool) -> Bool) -> Bool {
return combine(a, b)
}

let result = combineWith(false, true, { $0 || $1 } )

Defining logical operator implies in lua

OOP-style calls

This gets rather hacky if it must truly be infix. What about simply using metatables for OOP-ish object:method(params) syntax?

Assuming implies is defined as

local function _implies(a, b)
if a ~= 0 then return b end
return 1
end

this would be implemented as

debug.setmetatable(0, {__index = {
implies = _implies
}})

and used as

i:implies(j)

if you want you a simpler dot syntax instead, consider using currying:

debug.setmetatable(0, {__index = {
implies = function(a) return function(b) return _implies(a, b) end end
}})

used as

i.implies(j)

A more "infix-ish" notation might be achieved by using the __call metamethod, and passing a function name:

debug.setmetatable(0, {__index = {
implies = function(a) return function(b) return _implies(a, b) end end
}, __call = function(self, index) return self[index] end})
(i)("implies")(j)

If implies = "implies", this can even be shortened to (i)(implies)(j).

Hacky, "truly" infix notation

If infix notation is of utmost importance, yet you can't use the available metamethods as they are limited and rather unreadable, you can use even more currying and workarounds to use other metamethods to create operators that seemingly turn your function (at least syntactically) into an infix operator using a "proxy" metatable instead of the function. You can use whatever operators you like; just make sure they suit your needs in terms of associativity and precedency:

local implies_right_hand_mt = {
__mul = function(self, b)
return _implies(self.a, b)
end
}
local implies_left_hand = setmetatable({}, {
__mul = function(a)
return setmetatable({a = a}, implies_right_hand_mt)
end
})
implies = implies_left_hand

The syntax would then be i *implies* j or "i *implies* j" in your example (using the multiplication operator). You could however use all other operators (except the comparison operators) as well, including other arithmetic operators, as implies is not a number but rather a table and may thus override number metamethods.

Side note

Consider using booleans instead of numbers. You'd get two advantages:

  1. Most metamethods aren't used by booleans (especially all arithmetic & bitwise metamethods);
  2. The logic operators not, and and or work; you don't have to use bitwise operators (although those work fine as well).

Explanation of zip, reduce and combine in Swift

zip(a, b) produces a sequence of tuples pairing the values from a and b

[(5, 3), (6, 6), (7, 10)]

That sequence is passed to reduce one tuple at a time. reduce takes two parameters. The first is the initial value for the runningTotal, and the second is a closure named combine which operates on each of the items in the sequence one call at a time.

In this case, the code is counting up the number of scores for Alice and Bob where their score is higher.

The use of default values $0, $1.0, and $1.1 makes the code a bit hard to interpret, but here is an equivalent version:

let pointsAlice = zip(a, b).reduce(0, combine: { (runningTotal, scores) in
return runningTotal + (scores.0 > scores.1 ? 1 : 0) } )

For each value in the sequence (such as (5, 3)), that value gets passed to the combine closure as scores, and the runningTotal gets the value from the previous iteration of reduce. scores.0 refers to the first value in the tuple, and scores.1 refers to the second value in the tuple. The initial runningTotal is the 0 that is passed to reduce.

The combine closure is returning the runningTotal plus 1 if the first score is higher, or plus 0 otherwise. That value is then passed into the next call of combine as the new runningTotal value along with the next scores tuple.

The final result is a count of scores where the first score is higher.

Swift: Combine condition and if-let with logical or

The equivalent to your code example would be:

if text == "" || Int(text) ?? 2 < 2 {
print("valid")
// do your previous "something
} else {
print("invalid")
}

which yields

"" -> valid

"1" -> valid

"2" -> invalid

"abc" -> invalid

Using Reduce to sum (Swift)

In a short way:

let reduced = array.reduce(0) { $1.isAvailable ? $0 + $1.bars.count : $0 }

Now, let's explicit it:

The logic is quite simple:

  • We set the initial value to 0
  • In the closure, we have two parameters, the first one is the current value (at start it's the initial value), which we'll increment at each iteration, and the second one is the element of the array. We return then the new value (partial) that we incremented or not according to your condition (here is isAvailable)

Explicitly:

let reduced2 = array.reduce(0) { partial, current in
if current.isAvailable {
return partial + current.bars.count
} else {
return partial
}
}

With a ternary if:

let reduced3 = array.reduce(0) { partial, current in
return current.isAvailable ? partial + current.bars.count : partial
}

Getting rid of the return, see Functions With an Implicit Return in Functions of Swift or Implicit Returns from Single-Expression Closures of Closures of Swift.

let reduced4 = array.reduce(0) { partial, current in
current.isAvailable ? partial + current.bars.count : partial
}

With Shorthand Argument Names on Closures of Swift.

let reduced5 = array.reduce(0) { $1.isAvailable ? $0 + $1.bars.count : $0 }

What aren't these two ways of expressing map function equivalent?

Looks like the Int.init overload that accepts a Substring has the following signature:

public init?<S>(_ text: S, radix: Int = 10) where S : StringProtocol

So, Int($0) works because it uses the default radix, but there isn't an Int.init(_:) that accepts a Substring - there's only Int.init(_:radix:) that does - and so it fails.

But if there was one:

extension Int {
public init?<S>(_ text: S) where S : StringProtocol {
self.init(text, radix: 10)
}
}

then this would work:

let result1 = arr.compactMap(Int.init)


Related Topics



Leave a reply



Submit