 
 // MARK: Signals that emit other signals
 
+public enum FlattenStrategy {
+
+  /// Flatten the signal by observing and propagating emissions only from latest signal.
+  /// Previous signal observation gets disposed is such exists.
+  case latest
+
+  /// Flatten the signal by sequentially observing inner signals in order in which they
+  /// arrive, starting next observation only after previous one completes.
+  case concat
+
+  /// Flatten the signal by observing all inner signals and propagating events from each one as they arrive.
+  case merge
+}
+
 public extension SignalProtocol where Element: SignalProtocol, Element.Error == Error {
 
   public typealias InnerElement = Element.Element
 
-  /// Flatten the signal by observing all inner signals and propagate events from each one as they come.
+  /// Flatten the signal with the given strategy.
+  public func flatten(_ strategy: FlattenStrategy) -> Signal<InnerElement, Error> {
+    switch strategy {
+    case .merge:
+      return merge()
+    case .latest:
+      return switchToLatest()
+    case .concat:
+      return concat()
+    }
+  }
+
+  /// Flatten the signal by observing all inner signals and propagating events from each one as they arrive.
   public func merge() -> Signal<InnerElement, Error> {
     return Signal { observer in
       let lock = NSRecursiveLock(name: "com.reactivekit.merge")

    }
  }

  /// Maps each element into an optional type and propagates unwrapped .some results.
  /// Shorthand for ```map().ignoreNil()```.
  public func flatMap<U>(_ transform: @escaping (Element) -> U?) -> Signal<U, Error> {
    return Signal { observer in
      return self.observe { event in
        switch event {

  /// Usually used on the Signal resulting from `materialize()`.
  /// - SeeAlso: `errors()`, `materialize()`
  public func elements<U, E>() -> Signal<U, NoError> where Element == Event<U, E> {
    return compactMap { $0.element }
  }

  /// Returns an observable sequence containing only the unwrapped errors from `.failed` events.
  /// Usually used on the Signal resulting from `materialize()`.
  /// - SeeAlso: `elements()`, `materialize()`
  public func errors<U, E>() -> Signal<E, NoError> where Element == Event<U, E> {
    return compactMap { $0.error }
  }
}

