public enum Vertex: CustomDebugStringConvertible, CustomStringConvertible { indirect case XY(Element, Memo, Memo) case End public func analysis(@noescape ifXY ifXY: (Element, Memo, Memo) -> Result, @noescape ifEnd: () -> Result) -> Result { switch self { case let .XY(a, x, y): return ifXY(a, x, y) case .End: return ifEnd() } } public var isEmpty: Bool { return analysis(ifXY: const(false), ifEnd: const(true)) } public var element: Element? { return analysis( ifXY: { x, _, _ in x }, ifEnd: const(nil)) } public var right: Memo { return analysis( ifXY: { _, xs, _ in xs }, ifEnd: const(Memo(evaluated: .End))) } public var down: Memo { return analysis( ifXY: { _, _, ys in ys }, ifEnd: const(Memo(evaluated: .End))) } public var diagonal: Memo { return right.flatMap { $0.down } } public var row: Stream { return Stream.unfold(Memo(evaluated: self)) { $0.value.analysis( ifXY: { here, across, _ in .Some(here, across) }, ifEnd: const(nil)) } } public var column: Stream { return Stream.unfold(Memo(evaluated: self)) { $0.value.analysis( ifXY: { here, _, down in .Some(here, down) }, ifEnd: const(nil)) } } public var rowMajor: Stream> { return Stream.unfold(Memo(evaluated: self), { (state: Memo) -> (Stream, Memo)? in state.value.analysis( ifXY: { _, _, down in (state.value.row, down) }, ifEnd: const(nil)) }) } public var columnMajor: Stream> { return Stream.unfold(Memo(evaluated: self), { (state: Memo) -> (Stream, Memo)? in state.value.analysis( ifXY: { _, across, _ in (state.value.column, across) }, ifEnd: const(nil)) }) } public init(rows: S1, columns: S2, combine: (S1.Generator.Element, S2.Generator.Element) -> Element) { let rows = Stream(sequence: rows) let columns = Stream(sequence: columns) func across(vertex: Vertex) -> Stream>> { return Stream.unfold(Memo(evaluated: vertex)) { vertex in vertex.value.analysis( ifXY: { _, xs, _ in .Some(vertex, xs) }, ifEnd: const(.Some(vertex, vertex))) } } self = rows .map { a in columns.map { b in combine(a, b) } } .fold(.End) { $0.zipWith(across($1.value)).fold(.End) { .XY($0.0, $1, $0.1) } } } public func map(transform: Element -> Other) -> Vertex { switch self { case let .XY(xy, xs, ys): return .XY(transform(xy), xs.map { $0.map(transform) }, ys.map { $0.map(transform) }) case .End: return .End } } public var debugDescription: String { return rowMajor.map { $0.map { String(reflecting: $0) }.joinWithSeparator("\t") }.joinWithSeparator("\n") } public var description: String { return rowMajor.map { $0.map { String($0) }.joinWithSeparator("\t") }.joinWithSeparator("\n") } } public func == (left: Vertex, right: Vertex) -> Bool { switch (left, right) { case (.End, .End): return true case let (.XY(a, x1, y1), .XY(b, x2, y2)): return a == b && x1.value == x2.value && y1.value == y2.value default: return false } }