Introduce Functional operators Map (`|>`) , Dissolve (`=>`), and Unwrapped (`<?`)


(Holly Schilling) #1

Introduction

With the acceptance of SE-0235 (Add Result to Standard Library), Swift added another type to the Standard Library that implements a map(_ : ) function. This is a growing pattern and builds upon the functional aspects of Swift. As such, it seems logical to formalize some of these behaviors so that we can optimize code and enhance productivity.

Proposal

This proposal is to add three operators into the Standard Library, Map (|>), Dissolve (=>), and Unwrap (<?). The Map operator utilizes the Result type to wrap transformations while deferring error handling until the end of the chain. At the end of the chain, the Unwrap operator attempts to unwrap the Result completing the function, or the Dissolve operator forwards the result to a completion function.

Additional implementations could be added to map Array, Optional, and Dictionary types with the same syntax, but wrapping and unwrapping the Result each step would be necessary for each type.

infix operator |> : LogicalDisjunctionPrecedence
infix operator => : LogicalDisjunctionPrecedence
postfix operator <?

public func |> <Source, Target> (lhs: Source, rhs: (Source) throws -> Target) -> Result<Target, Error>
{
    return Result {
        try rhs(lhs)
    }
}

public func |> <Source, Target> (lhs: Result<Source, Error>, rhs: (Source) throws -> Target) -> Result<Target, Error>
{
    return Result {
        let source = try lhs.unwrapped()
        return try rhs(source)
    }
}

public func => <Source> (lhs: Source, rhs: (Source) -> Void)
{
    rhs(lhs)
}

public postfix func <? <Value> (lhs: Result<Value, Error>) throws -> Value
{
    return try lhs.unwrapped()
}

Usage


func foo(_ : A) throws -> B {..}
func bar(_ : B) throws -> C {..}
func dissolveC(_ : Result<C, Error>) { .. }

func useDissolve(startValue: A) {
    startValue 
        |> foo
        |> bar
        => dissolveC
}

func useUnwrap(startValue: A) throws -> C {
    return startValue
        |> foo
        |> bar <?
}


(Sven) #2

Please don’t. Those operators may be obvious to someone coming from other functional languages that use them, but for the rest this is unreadable.

Many people struggle with those functional concepts. Having them hidden behind some operators (for which you currently can’t even look up the documentation in Xcode) doesn’t make them more approachable.