Global Function Sequence(State:Next:) and Type Inference

Global function sequence(state:next:) and type inference

This looks like a combination of two issues.

The first is that Swift currently doesn't infer the type of a multi-line closure without any external context. This is however intended behaviour, as confirmed by Apple developer Jordan Rose in the comments of SR-1570:

This is correct behavior: Swift does not infer parameter or return types from the bodies of multi-statement closures. But the diagnostic could be a lot better.

Therefore in theory, you would just need to explicitly define the return type of the closure you pass to sequence()'s next: parameter, as the parameter type can be inferred from external context (namely the type you pass into the state: parameter):

let seq1 = 1...3
let seq2 = 4...6

let combined = sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
next: { iters -> Int? in
iters.0 = !iters.0
return iters.0 ? iters.1.next() : iters.2.next()
})

(Edit: This now compiles in Swift 3.1)


However, this still doesn't compile – which is due to the second issue, where the compiler cannot infer the type for an inout closure parameter in Swift 3 (which wasn't the case in Swift 2). This is a suspected bug, which has already been filed (see both SR-1976 & SR-1811).

Therefore, as you note in the question, this means (quite unsatisfactorily) that you have to explicitly annotate the full closure signature that you pass to next::

let combined = sequence(state: (false, seq1.makeIterator(), seq2.makeIterator()),
next: { (iters: inout (Bool, ClosedRangeIterator<Int>, ClosedRangeIterator<Int>)) -> Int? in
iters.0 = !iters.0
return iters.0 ? iters.1.next() : iters.2.next()
})

Why can't I get type-specific information in my Sequence extension?

String is a struct and not a class or a protocol, so the syntax Iterator.Element : String doesn't make sense since Iterator.Element can't be a subclass of String or implement the protocol String. Instead, use Iterator.Element == String:

extension Sequence where Iterator.Element == String {
var onlyDumbOnes: [String] {
return self.filter { (string) -> Bool in
if string.hasPrefix("Dumb") {
return true
}
return false
}
}
}

One-liner to generate Powerball picks in Swift?

Xcode 10 • Swift 4.2

Swift now has added shuffled() to ClosedRange and random(in:) to Int which now makes this easily accomplished in one line:

func pball() -> [Int] {
return (1...69).shuffled().prefix(5).sorted() + [Int.random(in: 1...26)]
}

Further trimmings:

Because of the return type of pball(), the Int can be inferred in the random method call. Also, .prefix(5) can be replaced with [...4]. Finally, return can be omitted from the one-line function:

func pball() -> [Int] {
(1...69).shuffled()[...4].sorted() + [.random(in: 1...26)]
}

Swift running sum

The general combinator you're looking for is often called scan, and can be defined (like all higher-order functions on lists) in terms of reduce:

extension Array {
func scan<T>(initial: T, _ f: (T, Element) -> T) -> [T] {
return self.reduce([initial], combine: { (listSoFar: [T], next: Element) -> [T] in
// because we seeded it with a non-empty
// list, it's easy to prove inductively
// that this unwrapping can't fail
let lastElement = listSoFar.last!
return listSoFar + [f(lastElement, next)]
})
}
}

(But I would suggest that that's not a very good implementation.)

This is a very useful general function, and it's a shame that it's not included in the standard library.

You can then generate your cumulative sum by specializing the starting value and operation:

let cumSum = els.scan(0, +)

And you can omit the zero-length case rather simply:

let cumSumTail = els.scan(0, +).dropFirst()

Why may we use internal argument labels in type annotations of closures, when they (seemingly) can never be accessed?

What you're observing is the ability to define "purely cosmetic" parameter labels for closure types. This was accepted as a part of SE-0111, as stated in the rationale:

In response to community feedback, the core team is accepting the proposal with a revision to allow “purely cosmetic” parameter labels in closure types for documentation (as outlined in the alternatives section).

The syntax for these cosmetic parameter labels changed after the proposal to require an argument label of _, in order to make it explicit that the cosmetic labels aren't used at the call-site. This was detailed in an additional commentary:

The specific revision requested by the core team to SE-0111 is that
all “cosmetic” labels should be required to include an API name of _.
For example, this would not be allowed:

var op : (lhs : Int, rhs : Int) -> Int

instead, it should be spelled as:

var op : (_ lhs : Int, _ rhs : Int) -> Int

Although really, in practice, this makes the cosmetic labels fairly useless, as they don't show up at the call-site or even in auto-completion – only at the actual declaration itself. Therefore their intent to be self-documenting is somewhat lost.

The Swift team are aware of this shortcoming, and will be looking to make a purely additive change post-Swift 3 in order to rectify the situation.

Here's the sketch that they proposed (again, in the additional commentary):

First, we extend declaration names for variables, properties, and parameters to allow parameter names as part of their declaration name. For example:

var op(lhs:,rhs:) : (Int, Int) -> Int    // variable or property.
x = op(lhs: 1, rhs: 2) // use of the variable or property.

// API name of parameter is “opToUse”, internal name is "op(lhs:,rhs:)”.
func foo(opToUse op(lhs:,rhs:) : (Int, Int) -> Int) {
x = op(lhs: 1, rhs: 2) // use of the parameter
}
foo(opToUse: +) // call of the function

This will restore the ability to express the idea of a closure
parameter that carries labels as part of its declaration, without
requiring parameter labels to be part of the type system (allowing,
e.g. the operator + to be passed into something that requires
parameter labels).

Second, extend the rules for function types to allow parameter API
labels if and only if they are used as the type of a declaration
that allows parameter labels, and interpret them as a sugar form for
providing those labels on the underlying declaration. This means that
the example above could be spelled as:

var op : (lhs: Int, rhs: Int) -> Int    // Nice declaration syntax
x = op(lhs: 1, rhs: 2) // Same as above

// API name of parameter is “opToUse”, internal name is "op(lhs:,rhs:)”.
func foo(opToUse op : (lhs: Int, rhs: Int) -> Int) {
x = op(lhs: 1, rhs: 2) // Same as above.
}
foo(opToUse: +) // Same as above.

This proposed solution quite nicely allows the labels to be used at the call-site, allowing for self-documenting parameter labels, while not complicating the type-system with them. Additionally (in most cases) it allows for the expressive syntax of writing the labels next to the parameter types of the closure – which we were used to doing pre-Swift 3.

Is there a way to use C variadic functions with the latest Swift 3 snapshot?

The only way to get around this is to create a wrapper function in C that is not variadic. However, an effort is underway to create wrappers for the functions in Darwin that need it, and recently multiple were added for ioctl by this commit.

To use the wrapper, you need to have a swift version at least as new as the June 22nd snapshot. Make sure you are using that toolchain.

Ambiguous reference to member 'Int.init'

Need to give compiler more information about the type solved my issues. Thanks for your help.

 var updatedTask : [String : Any] = 
[
"description": self.descriptionTextfield.text!, // <- HERE
"title": self.titleTextfield.text!, // <- HERE
"priority": self.priorityTextfield.text!.uppercaseString,
"type": self.typeTextfield.text!.uppercaseString,
"dueDate": Int(date.timeIntervalSince1970 * 1000),
"privacy": self.privateSwitch.on ? "PRIVATE": "PUBLIC"
]

Subtraction of CGFloats, ambiguity error Swift 3

I can't find the bug report, but this is a known bug. A workaround is to cast the first or the second variable to a non-optional, like so:

(screenHeight as CGFloat) - panelHeight - tabBarHeight

Why is type inference impractical for object oriented languages?

When using nominal typing (that is a typing system where two classes whose members have the same name and the same types are not interchangeable), there would be many possible types for a method like the following:

let f(obj) =
obj.x + obj.y

Any class that has both a member x and a member y (of types that support the + operator) would qualify as a possible type for obj and the type inference algorithm would have no way of knowing which one is the one you want.

In F# the above code would need a type annotation. So F# has object orientation and type inference, but not at the same time (with the exception of local type inference (let myVar = expressionWhoseTypeIKNow), which always works).



Related Topics



Leave a reply



Submit