Simplifying Swift Enum - swift

After experimenting with currying in Swift, I came up with the code below. I want to see if it's possible to simplify this enum Operate. Currently, I need to initialize like this:
let multiply = Operate.Multiply.op
I would prefer to have each case have an associated value that directly returns a closure without having to do this hacky switch block. Is this possible?
Here's some code that you can run in a Swift playground:
import Foundation
enum Operate {
case Plus
case Minus
case Multiply
case unsafeDivide
var op: (Double) -> (Double) -> Double {
get {
switch self {
case .Plus:
return { n in
return { n + $0}
}
case .Minus:
return { n in
return { n - $0}
}
case .Multiply:
return { n in
return { n * $0}
}
case .unsafeDivide:
return { n in
return { n / $0 }
}
}
}
}
}
let multiply = Operate.Multiply.op
let plus = Operate.Plus.op
let unsafeDivide = Operate.unsafeDivide.op
// 3 + (16 * 2) -> 35
plus(3)(multiply(16)(2))
Bonus: How can I handle errors with unsafeDivide in a 'Swiftly' manner, that is, prevent this:
let unsafeDivide = Operate.unsafeDivide.op
unsafeDivide(2)(0)

What you seem to be doing is currying. You remove a lot of duplicated code by extracting a curry function:
func curry<A,B,C>(_ f: #escaping (A, B) -> C) -> (A) -> (B) -> C {
return { a in { b in f(a, b) } }
}
// ...
var op: (Double) -> (Double) -> Double {
switch self {
case .plus: // please follow Swift naming conventions, enum cases start with a lowercase
return curry(+)
case .minus:
return curry(-)
case .multiply:
return curry(*)
case .unsafeDivide:
return curry(/)
}
}
That already looks a lot nicer. You seem to not like switch statements, so here's how you'd do it with a dictionary:
var op: (Double) -> (Double) -> Double {
let dict: [Operate: (Double, Double) -> Double] =
[.plus: (+), .minus: (-), .multiply: (*), .unsafeDivide: (/)]
return curry(dict[self]!)
}
In fact, you can use the new callAsFunction feature in Swift 5.2 to omit even the word op on the caller side:
func callAsFunction(_ a: Double) -> (Double) -> Double {
op(a)
}
This allows you to do:
Operator.multiply(2)(3)
Using associated values is another way:
enum Operate {
case plus(Double)
case minus(Double)
case multiply(Double)
case unsafeDivide(Double)
func callAsFunction(_ b: Double) -> Double {
switch self {
case .plus(let a):
return a + b
case .minus(let a):
return a - b
case .multiply(let a):
return a * b
case .unsafeDivide(let a):
return a / b
}
}
}
But I personally don't like it because having associated values means that you can't simply use == to compare enum values, among other restrictions.
Preventing dividing by 0 at compile time is impossible, because the values you pass in might not be compile time constants. If you just want to check for compile time constants, then you might need a static code analyser like SwiftLint. At runtime, division of the Double 0 is well-defined by the IEEE standard anyway. It won't crash or anything.

Related

Spread variable parameter count on generic function

In javascript it is pretty easy to take a variable count of arguments and pass it to a sub function without the need to modify the sub function. For example, you want to write a wrapper function which takes a generic function as first argument and calls it with the rest of the arguments:
function wrapper(func, ...args) {
return func(...args)
}
I want to archive something similar in swift. There I have many many c function which I want to wrap with another function for some safety reasons.
Now I have two major road blockers:
The first one: I don't know how to do something like func(...args) in swift. This is why I temporary tried this:
private func apply<ReturnValue, FunctionParams>(_ fun: (_ params: FunctionParams...) -> ReturnValue, _ paramsPass: [FunctionParams]) throws -> ReturnValue {
switch paramsPass.count {
case 0:
return fun()
case 1:
return fun(paramsPass[0])
case 2:
return fun(paramsPass[0], paramsPass[1])
case 3:
return fun(paramsPass[0], paramsPass[1], paramsPass[2])
case 4:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3])
case 5:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3], paramsPass[4])
case 6:
return fun(paramsPass[0], paramsPass[1], paramsPass[2], paramsPass[3], paramsPass[4], paramsPass[5])
default:
throw NSError(domain: "apply", code: paramsPass.count, userInfo: nil);
}
}
This is not really good and only works for a max parameter count of 6.
The second road blocker is, I am not able to write the required swift types to archive something like I described. This is what I tried:
private func runUnsafeFunction<ReturnValue, FunctionParams>(_ fun: (_ params: FunctionParams...) -> ReturnValue, _ paramsPass: FunctionParams...) throws -> ReturnValue {
// wrapper code
return try apply(fun, paramsPass)
}
However, if I try to call it, I get: Generic parameter 'ReturnValue' could not be inferred
Probably I miss something here. But at this point I am stuck.
Why not pass the function and its arguments in a closure?
func runUnsafeFunction<ReturnValue>(function: () -> ReturnValue) -> ReturnValue {
// do stuff
return function()
}
Example
func add(_ a: Int, _ b: Int) -> Int {
a + b
}
func add(_ a: Int, _ b: Int, _ c: Int) -> Int {
a + b + c
}
let result = runUnsafeFunction { add(3, 4) }
let result2 = runUnsafeFunction { add(3, 4, 5) }

Defining a generic unfoldr function

func unfoldr<A, B>(_ f: #escaping (B) -> (A, B)?) -> (B) -> UnfoldFirstSequence<A> {
return { b in sequence(
first: b, next: { x in
switch f(x) {
case .some(let(a, b)):
return Optional(a)
default:
return Optional.none
}
}
)
}
}
With this definition, I am getting the following error:
Cannot convert value of type 'B' to expected argument type 'A'.
Is there some way of solving this issue and definining this function ?
Your sequence doesn't seem to be a UnfoldFirstSequence. Your sequence seems to have a state B, and f is responsible for producing a new state and an element for the sequence. An UnfoldFirstSequence has no state that you can control. You can only produce the next element from the previous element.
Your sequence can be modelled by the more general UnfoldSequence, which has a State generic parameter. In fact, an UnfoldFirstSequence<T> is just an UnfoldSequence<T, (T?, Bool)>! See why the former is a special case of the latter by reading the source code :)
You can create such a sequence using sequence(state:next:).
func unfoldr<A, B>(_ f: #escaping (B) -> (A, B)?) -> (B) -> UnfoldSequence<A, B> {
return {
sequence(state: $0) { x in
guard let (a, b) = f(x) else {
return nil
}
x = b
return a
}
}
}
Example:
let seq = unfoldr { x -> (String, Int)? in
if x == 10 {
return nil
} else {
return ("\(x)", x + 1)
}
}
seq(0).forEach { print($0) }

Creating an enum instance

suppose I have
enum Example {
case one(string: String)
case two(string: String)
}
and now I have
let x = Example.one(string: "Hello")
The question:
let y = ?
how do I create another instance of the same enum in e, so that I end up with y == .one("World"))
The types of enum cases with associated values are closures with arguments corresponding to the type of the associated values, and with a return corresponding to the type of the enum (with the value of the return being the specific case). I.e., for your example above, the type of Example.one as well as Example.two is (String) -> Example, where the closures expressed by these two cases yield different results; instances of .one(...) and .two(...), respectively.
Hence, instead of writing your own method to "clone" a given case, you could simply have a computed property which returns the already existing closures Example.one and Example.two (if self is one or two, respectively), which can subsequently be invoked upon a String argument to construct a new Example instance (with value .one or .two; along with the supplied associated String value).
E.g.:
enum Example {
case one(string: String) // type: (String) -> Example
case two(string: String) // type: (String) -> Example
var caseClosure: (String) -> Example {
switch self {
case .one: return Example.one
case .two: return Example.two
}
}
}
let x = Example.one(string: "Hello") // .one("Hello")
let y = x.caseClosure("World") // .one("World")
However, since all the cases in your example are closures of the same type, namely (String) -> Example (i.e. have the same number and type(s) of associated values), you might as well, as already proposed in a comment by #Hamish, wrap an enum with no associated values in a struct along with the always-String "associated value" a separate member of the struct. E.g. expanding Hamish's example with some initializers:
struct S {
enum E {
case one
case two
}
var e: E
var string: String // Since "associated value" is always the same type
init(_ e: E, string: String) {
self.e = e
self.string = string
}
init(from s: S, string: String) {
self.e = s.e
self.string = string
}
}
let x = S(.one, string: "Hello")
let y = S(from: x, string: "World")
let z = S(x.e, string: "World")
You do that by calling the Initializer exactly like you did for x:
enum Example {
case one(string: String)
case two(string: String)
}
let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")
let y = Example.one(string: "World")
print(y) // Prints one("World")
Also, The , in your enum declaration is wrong and has to be removed.
UPDATE:
The comment explained the question in more detail, so here is my updated answer:
An elegant way to solve this is to use a function on the original enum type Example.
enum Example {
case one(string: String)
case two(string: String)
func cloneWith(string: String) -> Example {
switch self {
case .one:
return .one(string: string)
case .two:
return .two(string: string)
}
}
}
let x = Example.one(string: "Hello")
print(x) // Prints one("Hello")
let y = x.cloneWith(string: "World")
print(y) // Prints one("World")

Generic factory method and type inference

I have the following class with a generic factory method:
final class Something<T> {
let value: T
init(initial: T) {
value = initial
}
}
extension Something {
class func zip<A, B>(_ a: A, _ b: B) -> Something<(A, B)> {
let initial = (a, b)
return Something<(A, B)>(initial: initial)
}
}
How come I can’t call zip without explicitly specifying the return type?
// ERROR: Cannot invoke `zip` with an argument list of type `(Int, Int)`
let y = Something.zip(1, 2)
// OK: Works but it’s unacceptable to require this on caller's side
let x = Something<(Int, Int)>.zip(1, 2)
Thank you for your time!
The reason you're seeing this is that there's nothing in this call:
let y = Something.zip(1, 2)
That tells Swift what T should be.
Your call implicitly specifies what A and B should be, and specifies the method should return Something<A, B>. But that Something<A, B> is not connected to Something<T>.
In fact, nothing at all in your call is connected to T; T is left unspecified, so it could be anything. I mean that literally—you can actually put (nearly) any random type in the angle brackets after Something and it'll work exactly the same:
let y = Something<UICollectionViewDelegateFlowLayout>.zip(1, 2)
What you would really like to do is somehow specify that T has to be a tuple and the two parameters are of the same types as the tuple's elements. Unfortunately, Swift doesn't currently have the features needed to properly do that. If the language were more sophisticated, you could say something like this:
extension<A, B> Something where T == (A, B) {
class func zip(a: A, _ b: B) -> Something {
let initial = (a, b)
return Something(initial: initial)
}
}
But for now, you'll have to make do with this horrible hack, which works by meaninglessly reusing the T type parameter so that it's no longer at loose ends:
extension Something {
class func zip<B>(a: T, _ b: B) -> Something<(T, B)> {
let initial = (a, b)
return Something<(T, B)>(initial: initial)
}
}
In short explanation, you use generics not correct. It's not realtime feature, it's precompile thing. If you need to make abstract class from generic input values, see and do like this:
class Abstract<T> {
init(value: T) {
print("inputed value: \(value)")
}
}
class Something {
class func zip<A, B>(value: A, value2: B) -> Abstract<(A, B)> {
print("Something.zip", value, value2)
return Abstract<(A, B)>(value: (value, value2))
}
}
Something.zip(5, value2: 40) // "inputed value: (5, 40)"
T simply isn't related to A and B in that way and so can't be inferred.
Eg.
let z = Something<(String, String)>.zip(1, 2)
let z2 = Something<AnyObject>.zip(1, 2)
work just fine to return a Something<(Int, Int)>
You can introduce type inference for your case like this:
final class Something<T> {
let value: T
init(initial: T) {
value = initial
}
class func zip<A, B>(_ a: A, _ b: B) -> Something<T> where T == (A, B) {
let initial = (a, b)
return Something<(A, B)>(initial: initial)
}
}
let y = Something.zip(1, 2) //works

Avoid consecutive "if let" declarations in Swift [duplicate]

This question already has answers here:
Using multiple let-as within a if-statement in Swift
(3 answers)
Closed 6 years ago.
In Swift I used if let declarations to check if my object is not nil
if let obj = optionalObj
{
}
But sometimes, I have to face with consecutive if let declarations
if let obj = optionalObj
{
if let a = obj.a
{
if let b = a.b
{
// do stuff
}
}
}
I'm looking for a way to avoid consecutive if let declarations.
I would try something like :
if let obj = optionalObj && if let a = obj.a && if let b = a.b
{
// do stuff
}
But the swift compiler do not allow this.
Any suggestion ?
Update
In swift 1.2 you can do
if let a = optA, let b = optB {
doStuff(a, b)
}
Original answer
In your specific case, you can use optional chaining:
if let b = optionaObj?.a?.b {
// do stuff
}
Now, if you instead need to do something like
if let a = optA {
if let b = optB {
doStuff(a, b)
}
}
you're out of luck, since you can't use optional chaining.
tl; dr
Would you prefer a cool one-liner instead?
doStuff <^> optA <*> optB
Keep reading. For how scaring it might look, this is really powerful and not so crazy to use as it seems.
Fortunately, this is a problem easily solved using a functional programming approach. You can use the Applicative abstraction and provide an apply method for composing multiple options together.
Here's an example, taken from http://robots.thoughtbot.com/functional-swift-for-dealing-with-optional-values
First we need a function to apply a function to an optional value only only when it contains something
// this function is usually called fmap, and it's represented by a <$> operator
// in many functional languages, but <$> is not allowed by swift syntax, so we'll
// use <^> instead
infix operator <^> { associativity left }
func <^><A, B>(f: A -> B, a: A?) -> B? {
switch a {
case .Some(let x): return f(x)
case .None: return .None
}
}
Then we can compose multiple options together using apply, which we'll call <*> because we're cool (and we know some Haskell)
// <*> is the commonly-accepted symbol for apply
infix operator <*> { associativity left }
func <*><A, B>(f: (A -> B)?, a: A?) -> B? {
switch f {
case .Some(let value): return value <^> a
case .None: return .None
}
}
Now we can rewrite our example
doStuff <^> optA <*> optB
This will work, provided that doStuff is in curried form (see below), i.e.
func doStuff(a: A)(b: B) -> C { ... }
The result of the whole thing is an optional value, either nil or the result of doStuff
Here's a complete example that you can try in the playground
func sum(a: Int)(b: Int) -> Int { return a + b }
let optA: Int? = 1
let optB: Int? = nil
let optC: Int? = 2
sum <^> optA <*> optB // nil
sum <^> optA <*> optC // Some 3
As a final note, it's really straightforward to convert a function to its curried form. For instance if you have a function taking two parameters:
func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {
return { a in { b in f(a,b) } }
}
Now you can curry any two-parameter function, like + for example
curry(+) <^> optA <*> optC // Some 3
I wrote a little essay on the alternatives some time ago: https://gist.github.com/pyrtsa/77978129090f6114e9fb
One approach not yet mentioned in the other answers, which I kinda like, is to add a bunch of overloaded every functions:
func every<A, B>(a: A?, b: B?) -> (A, B)? {
switch (a, b) {
case let (.Some(a), .Some(b)): return .Some((a, b))
default: return .None
}
}
func every<A, B, C>(a: A?, b: B?, c: C?) -> (A, B, C)? {
switch (a, b, c) {
case let (.Some(a), .Some(b), .Some(c)): return .Some((a, b, c))
default: return .None
}
}
// and so on...
These can be used in if let statements, case expressions, as well as optional.map(...) chains:
// 1.
var foo: Foo?
if let (name, phone) = every(parsedName, parsedPhone) {
foo = ...
}
// 2.
switch every(parsedName, parsedPhone) {
case let (name, phone): foo = ...
default: foo = nil
}
// 3.
foo = every(parsedName, parsedPhone).map{name, phone in ...}
Having to add the overloads for every is boilerplate'y but only has to be done in a library once. Similarly, with the Applicative Functor approach (i.e. using the <^> and <*> operators), you'd need to create the curried functions somehow, which causes a bit of boilerplate somewhere too.
In some cases you can use optional chaining. For your simple example:
if let b = optionalObj?.a?.b {
// do stuff
}
To keep your nesting down and to give yourself the same variable assignments, you could also do this:
if optionalObj?.a?.b != nil {
let obj = optionalObj!
let a = obj.a!
let b = a.b!
}
After some lecture thanks to Martin R, I found an interesting workaround: https://stackoverflow.com/a/26012746/2754218
func unwrap<T, U>(a:T?, b:U?, handler:((T, U) -> ())?) -> Bool {
switch (a, b) {
case let (.Some(a), .Some(b)):
if handler != nil {
handler!(a, b)
}
return true
default:
return false
}
}
The solution is interesting, but it would be better if the method uses variadic parameters.
I naively started to create such a method:
extension Array
{
func find(includedElement: T -> Bool) -> Int?
{
for (idx, element) in enumerate(self)
{
if includedElement(element)
{
return idx
}
}
return nil
}
}
func unwrap<T>(handler:((T...) -> Void)?, a:T?...) -> Bool
{
let b : [T!] = a.map { $0 ?? nil}
if b.find({ $0 == nil }) == nil
{
handler(b)
}
}
But I've this error with the compiler: Cannot convert the expression's type '[T!]' to type '((T...) -> Void)?'
Any suggestion for a workaround ?