Composition without Operators

Episode #11 • Apr 9, 2018 • Subscriber-Only

While we unabashedly promote custom operators in this series, we understand that not every codebase can adopt them. Composition is too important to miss out on due to operators, so we want to explore some alternatives to unlock these benefits.

Composition without Operators
Introduction
00:05
Outroducing |>
00:57
Outroducing >>>
03:22
Outroducing >=>
07:16
Outroducing <>
11:49
Algebraic properties
15:53
What’s the point?
19:21
Next episode

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Introduction

Our series unabashedly promotes the use of custom operators, but they’re far from common in the Swift community. Our use of operators may even be the most controversial aspect of our series! We explored the “why” of operators in our first episode, and we continue to justify the operators we introduce with specific—maybe even rigorous—criteria, and while we may have you convinced, it’s another story to convince your coworkers! Your team may even adopt a style guide that prohibits it!

Operators shouldn’t be the bottleneck to introducing composition to your code. In this episode we’ll explore a few alternatives that may act as a more gentle introduction to the team and may even be the first step to getting your coworkers first-class tickets on the operator express!

This episode is for subscribers only.

Subscribe to Point-Free

Access this episode, plus all past and future episodes when you become a subscriber.

See plans and pricing

Already a subscriber? Log in

Exercises

  1. Write concat for functions (inout A) -> Void.

    Solution
    func concat<A>(
      _ f: @escaping (inout A) -> Void,
      _ g: @escaping (inout A) -> Void,
      _ fs: ((inout A) -> Void)...
      ) -> (inout A) -> Void {
    
      return { a in
        f(&a)
        g(&a)
        fs.forEach { $0(&a) }
      }
    }
    
  2. Write concat for functions (A) -> A.

    Solution
    func concat<A>(
      _ f: @escaping (A) -> A,
      _ g: @escaping (A) -> A,
      _ fs: ((A) -> A)...)
      -> (A) -> A {
    
        return { a in
          ([f, g] + fs).reduce(a, { $1($0) })
        }
    }
    
  3. Write a function called compose for backward composition. Recreate some of the examples from our functional setters episodes (part 1 and part 2) using compose and pipe.

    Solution
    func compose<A, B, C>(_ f: @escaping (B) -> C, _ g: @escaping (A) -> B) -> (A) -> C {
      return { f(g($0)) }
    }
    
    with(
      ((1, true), "Swift"),
      pipe(
        backPipe(first, first)(incr),
        backPipe(first, second)(!),
        second { $0 + "!" }
      )
    )
    
    with(
      (42, ["Swift", "Objective-C"]),
      pipe(
        first(incr),
        backPipe(second, map)({ $0.uppercased() })
      )
    )
    

References

Swift Overture

Brandon Williams & Stephen Celis • Monday Apr 9, 2018

We open sourced the Overture library to give everyone access to functional compositions, even if you can’t bring operators into your codebase.