Swift Sequence Anamorphism

102 views Asked by At

Does Swift's standard library include a list anamorphism for a Sequence or something similar?

An Anamorphism on lists or sequences would be the opposite of the reduce function. So instead of collapsing a sequence down to a single value, it will build a sequence up.

reduce takes an initial value, and a function for combining sequence elements with this, and returns a final value. It's signature looks like this (newlines added for readability):

public func reduce<Result>(
  _ initialResult: Result, 
  _ nextPartialResult: (Result, Self.Element) throws -> Result) rethrows
  -> Result

An anamorphism for sequence might go like this:

func inflate<State, Element>(
  _ initialState: State, 
  _ generator: @escaping (State) -> (State, Element)?)
  -> AnamorphismSequence<State, Element>

By giving it some initial state, and telling it how to turn that in to an element and the next state, it can build up a sequence for you. So, I could get an array such as Array(1..<10) like this:

Array(inflate(1) { s in s < 10 ? (s+1, s) : nil })
1

There are 1 answers

1
Alexander On BEST ANSWER

Swift has two variants of this. Both types have private initializers, but they can instead be generated using their respective global functions.

  1. UnfoldSequence<Element, State>, which is produced by sequence(state:next:)

  2. UnfoldFirstSequence<Element> which is produced by sequence(first:next:)

The latter doesn't do anything that can't be done by the former. It's merely a simplified version, that's used when you don't need a separate state, beyond merely knowing what the previous element was.

Here's how your 1..<10 example can be implemented, using both methods:

Array(sequence(first: 1) { i in (i < 9) ? (i + 1) : nil })

Array(sequence(state: 1) { state -> Int? in 
    defer { state += 1 }
    return state < 10 ? state : nil
})

Your example is better suited to the simpler sequence(first:next:). The latter would be more useful for something like a sequence that yields perfect squares: * Your maintained state would be the squares of the perfect squares (which increment by 1 with every unfold) * Your sequence yields it elements by multiplying that state by itself (to square it)

Technically, you could use a captured local variable to emulate the state of an UnfoldSequence, but that's quite a bit messier, and almost certainly slower.