I'm new to Swift. I was trying to implement a binary tree with recursive enumerations and generics:
enum BinaryTree<T> {
indirect case Node(T, BinaryTree<T>, BinaryTree<T>)
case Nothing
}
func inorder<T>(_ root: BinaryTree<T>) -> [T] {
switch root {
case .Nothing:
return []
case let .Node(val, left, right):
return inorder(left) + [val] + inorder(right)
}
}
Here's the error I got:
$ swift ADT.swift
ADT.swift:83:20: error: cannot convert value of type 'BinaryTree<T>' to expected argument type 'BinaryTree<_>'
return inorder(left) + [val] + inorder(right)
^~~~
However, this works:
func inorder<T>(_ root: BinaryTree<T>) -> [T] {
switch root {
case .Nothing:
return []
case let .Node(val, left, right):
let l = inorder(left)
let r = inorder(right)
return l + [val] + r
}
}
Is there any mistakes in my syntax? Thanks!
I'm using Swift 3.0.
Update
So I tried to condense the problem into minimal example code that fails to compile and asked a question myself and filed SR-4304. Turns out the answer is that this really is a bug in the compiler.
Original Answer
As far as I can tell, your syntax is perfectly valid. It seems that the Swift compiler’s type inference seems to need a nudge in the right direction which your second solution apparently provides. As I experienced several similar problems in the past, especially regarding the + operator, your question inspired me to try several other ways to join the arrays. These all work (I am just showing the return statements and supporting functions for the last three cases):
return (inorder(left) as [T]) + [val] + inorder(right)
return Array([inorder(left), [val], inorder(right)].joined())
return [inorder(left), [val], inorder(right)].reduce([], +)
return [inorder(left), [val], inorder(right)].flatMap { $0 }
func myjoin1<T>(_ arrays: [T]...) -> [T]
{
return arrays.reduce([], +)
}
return myjoin1(inorder(left), [val], inorder(right))
func myjoin2<T>(_ array1: [T], _ array2: [T], _ array3: [T]) -> [T]
{
return array1 + array2 + array3
}
return myjoin2(inorder(left), [val], inorder(right))
extension Array
{
func appending(_ array: [Element]) -> [Element]
{
return self + array
}
}
return inorder(left).appending([val]).appending(inorder(right))
Calling the operator as a function compiles, too:
return (+)(inorder(left), [val]) + inorder(right)
It would be great if somebody with more intimate knowledge of the Swift compiler could shed some light on this.
Related
I have an array of functions like
let array = [(Int) -> T?, (Int) -> T?, (Int) -> T?,...]
I need to get first non nil T value from array and I want 1 iteration for this task (O(n) will be the worst complexity). Anybody has neat ideas without for loops?
As I mentioned in my comment, there's no ready-made way to do this in Swift, so you have to at least implement something that uses a for loop.
If you want appearances at the call-site to look functional and not use a for loop, you can make the function extend Array like so:
extension Array {
func firstNonNilResult<V, T>(value: V) -> T? where Element == (V) -> T? {
for element in self {
if let t = element(value) {
return t
}
}
return nil
}
}
var array = [(Int) -> String?]()
func f(_ i: Int) -> String? {
print("called f() with \(i)")
return nil
}
func g(_ i: Int) -> String? {
print("called g() with \(i)")
return i == 5 ? "found it" : nil
}
array.append(f)
array.append(g)
if let t = array.firstNonNilResult(value: 5) {
print(t)
}
which prints:
called f() with 5
called g() with 5
found it
Whether or not this has any real-world utility I can't say. I think it's specialized enough that an Array extension seems like overkill, but your question is interesting so this is at least a potential solution.
Suppose you have two closures of type (Int)->() in Swift 3 and test to see if they are the same as each other:
typealias Baz = (Int)->()
let closure1:Baz = { print("foo \($0)") }
let closure2:Baz = { print("bar \($0)") }
if(closure1 == closure2) {
print("equal")
}
This fails to compile, giving the message:
Binary operator '==' cannot be applied to two '(Int)->()' operands
OK, well, how then can we compare two closures of the same type, to see if they are the same?
I'm pretty sure there is no way to determine if two closures are equal.
Obviously, a logical equality check is out of the question. That would be equivalent to finding an answer to the halting problem. (Just test to see if your code is equivalent to a piece of code that loops forever. If it is, it doesn't halt. If it isn't, it does halt.)
In theory you might expect the === operator to test if two closures are the exact same piece of code, but that gives an error when I try it in Playground.
Playground execution failed: error: MyPlayground.playground:1:20: error: cannot check reference equality of functions; operands here have types '(Int) -> ()' and '(Int) -> ()'
let bar = closure1 === closure2
~~~~~~~~ ^ ~~~~~~~~
Having thought about it, I'm sure the reason why that doesn't work is because you can't be sure that the closures really are equal. A closure is not just the code, but also the context in which it was created including any captures. The reason you can't check for equality is that there is no meaningful way in which two closures are equal.
To understand why thew captures are important, look at the following code.
func giveMeClosure(aString: String) -> () -> String
{
return { "returning " + aString }
}
let closure1 = giveMeClosure(aString: "foo")
let closure2 = giveMeClosure(aString: "bar")
Are closure1 and closure2 equal? They both use the same block of code
print(closure1()) // prints "returning foo"
print(closure2()) // prints "returning bar"
So they are not equal. You could argue that you can check the code is the same and the captures are the same, but what about
func giveMeACount(aString: String) -> () -> Int
{
return { aString.characters.count }
}
let closure3 = giveMeACount(aString: "foo")
let closure4 = giveMeACount(aString: "bar")
print(closure3()) // prints 3
print(closure4()) // prints 3
Apparently these closures are equal. It's not possible to implement any reasonable definition of equality that will work in every case, so Apple has instead not even tried. This is safer than providing an incomplete implementation that is wrong in some cases.
In the case where you want to track your own closures, uses them as Dictionary keys, etc., you can use something like this:
struct TaggedClosure<P, R>: Equatable, Hashable {
let id: Int
let closure: (P) -> R
static func == (lhs: TaggedClosure, rhs: TaggedClosure) -> Bool {
return lhs.id == rhs.id
}
var hashValue: Int { return id }
}
let a = TaggedClosure(id: 1) { print("foo") }
let b = TaggedClosure(id: 1) { print("foo") }
let c = TaggedClosure(id: 2) { print("bar") }
print("a == b:", a == b) // => true
print("a == c:", a == c) // => false
print("b == c:", b == c) // => false
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.
In order to use Swift in a functional style, how should we be dealing with head and tails of lists? Are Arrays and ArraySlices appropriate (seems like it since an ArraySlice is an efficient mechanism to get sublists)? Is the right mechanism to convert an Array to an ArraySlice and use .first! and .dropFirst() as equivalents for head and tail?
As an example of adding a list of numbers:
func add(_ nums: ArraySlice<Int>) -> Int {
if nums.count == 0 {
return 0
} else {
return nums.first! + add(nums.dropFirst())
}
}
Array has an initializer (init(_:)) that can produce an Array from any Sequence, such as an ArraySlice. However, using it forces a copy of the array data, which makes a simple sum algorithm like this to actually have O(nums.count^2) performance, even though it looks like it's only scanning through the array once.
func sum(_ nums: [Int]) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(Array(nums.dropFirst()))
}
let input = Array(1...10)
let output = sum(input)
print(output)
To get around this, a better implementation would instead just operate on ArraySlices, allowing copy-less slicing, but that requires the input Array first be converted into an ArraySlice. Luckily, an inner function can help make this transparent to the public API, but it does make the code longer.
func sum(_ nums: [Int]) -> Int {
func sum(_ nums: ArraySlice<Int>) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(nums.dropFirst())
}
return sum(ArraySlice(nums))
}
But really, as matt said, don't do this. The head/tail approach to programming makes sense in a language that facilitates it well with pattern matching, good compiler optimizations, tail call optimization, etc. Swift's design encourages using reduce. Not only is it shorter and much more readable, but it's also more performant.
For comparison, here's what a typical Swift approach would be to this:
extension Sequence where Iterator.Element: Integer {
func sum() -> Iterator.Element {
return self.reduce(0, +)
}
}
It's simpler and shorter.
It's polymorphic, so it'll work with any Sequence, rather than just being limited to Array
It's generic over any Integer type, not just Int. So these all work:
print(Array<UInt >(1...10).sum())
print(Array<UInt8 >(1...10).sum())
print(Array<UInt16>(1...10).sum())
print(Array<UInt32>(1...10).sum())
print(Array<UInt64>(1...10).sum())
print(Array< Int >(1...10).sum())
print(Array< Int8 >(1...10).sum())
print(Array< Int16>(1...10).sum())
print(Array< Int32>(1...10).sum())
print(Array< Int64>(1...10).sum())
However, if you insist on taking this head/tail approach, you can try one of these two techniques:
extension Collection {
func headTail1<Head, Tail, ReturnType>(_ closure: (Head?, Tail) -> ReturnType) -> ReturnType
where Head == Self.Element, Tail == Self.SubSequence {
return closure(self.first, self.dropFirst())
}
func headTail2<Head, Tail>() ->(Head?, Tail)
where Head == Self.Element, Tail == Self.SubSequence {
return (self.first, self.dropFirst())
}
}
func sum1<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
return nums.headTail1 { head, tail in
guard let head = head else { return 0 } //base case, empty list
return head + sum(tail)
}
}
func sum2<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
let (_head, tail) = nums.headTail2()
guard let head = _head else { return 0 } //base case, empty list
return head + sum(tail)
}
print(sum(Array(1...10)))
This code abstracts away the details of how the list is split into its head and tail, letting you write sum by only worrying about the head and tail that are provided for you.
The problem with your example is that you wouldn't use head and tail to add a list of numbers. You'd call reduce:
let nums = [1,2,3,4,5]
let sum = nums.reduce(0,+)
So, while I'm as fond of LISP / Scheme as the next man, you'll need a more compelling case of when we need head and tail, given that we have map, filter, and reduce (and so on).
I'd like to write an extension for tuples of (e.g.) two value in Swift. For instance, I'd like to write this swap method:
let t = (1, "one")
let s = t.swap
such that s would be of type (String, Int) with value ("one", 1). (I know I can very easily implement a swap(t) function instead, but that's not what I'm interested in.)
Can I do this? I cannot seem to write the proper type name in the extension declaration.
Additionally, and I suppose the answer is the same, can I make a 2-tuple adopt a given protocol?
You cannot extend tuple types in Swift.
According to
Types, there are named types (which
can be extended) and compound types. Tuples and functions are compound
types.
See also (emphasis added):
Extensions
Extensions add new functionality to an existing
class, structure, or enumeration type.
As the answer above states, you cannot extend tuples in Swift. However, rather than just give you a no, what you can do is box the tuple inside a class, struct or enum and extend that.
struct TupleStruct {
var value: (Int, Int)
}
extension TupleStruct : Hashable {
var hashValue: Int {
return hash()
}
func hash() -> Int {
var hash = 23
hash = hash &* 31 &+ value.0
return hash &* 31 &+ value.1
}
}
func ==(lhs: TupleStruct, rhs: TupleStruct) -> Bool {
return lhs.value == rhs.value
}
As a side note, in Swift 2.2, tuples with up to 6 members are now Equatable.
Details
Xcode 11.2.1 (11B500), Swift 5.1
Solution
struct Tuple<T> {
let original: T
private let array: [Mirror.Child]
init(_ value: T) {
self.original = value
array = Array(Mirror(reflecting: original).children)
}
func getAllValues() -> [Any] { array.compactMap { $0.value } }
func swap() -> (Any?, Any?)? {
if array.count == 2 { return (array[1].value, array[0].value) }
return nil
}
}
Usage
let x = (1, "one")
let tuple = Tuple(x)
print(x) // (1, "one")
print(tuple.swap()) // Optional((Optional("one"), Optional(1)))
if let value = tuple.swap() as? (String, Int) {
print("\(value) | \(type(of: value))") // ("one", 1) | (String, Int)
}
If you wanted to be a Bad Person™ you can define custom operators on tuples, like this:
postfix operator <->
postfix func <-> <A, B>(lhs: (A, B)) -> (B, A) {
return (lhs.1, lhs.0)
}
let initial = (1, "one")
let reversed = initial<->
FWIW I can't think of a place where my 'clever' code trumps the readability of just writing your swap function.