Skip to content

Instantly share code, notes, and snippets.

@Ben-G
Last active March 5, 2016 17:49
Show Gist options
  • Save Ben-G/aa080de6d61f46bdc842 to your computer and use it in GitHub Desktop.
Save Ben-G/aa080de6d61f46bdc842 to your computer and use it in GitHub Desktop.
Compose Types
// Example of a thing I cannot do with types in Swift
struct Operation<Input, Output> {
// would also be nice to have a list of operations that yield different types (and be able to dynamically inspect the generic type)
var operations: [Operation<>] = []
// This can be accomplished by using type erause
// would be nice to be able to leave a type hole here
var nextOperation: Operation<Output, _> // second generic argument can be any type from the perspective of this specific type
// only important aspect is that input of next operation matches output of this operation
// This can be accomplished partially by defining a function that only has a requirement for the first generic type
// when storing the value we however need to erase the type
// require `Output1` and `Output2` to be composed into a tuple output type `(Output1, Output2)`
// I don't think there's any way to accomplish this in Swift, except moving the composition from the type level
// to the value level?
init<Input, (Output1, Output2): Output, X>(op1: Operation<Input, Output1>, op2: Operation<Input, Output2>, nextOp: Operation<Output, X>) {
self.operations.append(op1)
self.operations.append(op2)
self.nextOperation = nextOp
}
init() {}
}
// High level idea:
let operationChain = Operation(
op1: Operation(op1: Operation<NoDependency,Int>, op2: Operation<NoDependency,String>,
nextOp: Operation<(Int,String), [Int]>()))
)
// second operation depends on two previous operations inputs
@jckarter
Copy link

jckarter commented Mar 5, 2016

class Operation<Input, Output> {
  func chain<NextOutput>(_ next: Operation<Output, NextOutput>)
      -> Operation<Input, NextOutput> {
    return ChainedOperation(self, next)
  }

  func apply(_ input: Input) -> Output {
    fatalError("abstract")
  }
}

class ChainedOperation<Input, Middle, Output>
    : Operation<Input, Output> {
  let left: Operation<Input, Middle>
  let right: Operation<Middle, Output>

  init(_ left: Operation<Input, Middle>,
       _ right: Operation<Middle, Output>) {
    self.left = left
    self.right = right
  }

  override func apply(_ input: Input) -> Output {
    let mid = left.apply(input)
    return right.apply(mid)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment