         return combineLatest(with: other.scan((), { _, _ in }).castError()) { my, _ in my }
     }
 
-    /// Emit elements from the receiver and the other signal in pairs.
-    /// This differs from `combineLatest` in that the combinations are produced from elements at same positions.
+    /// Combine the receiver and the `other` signal into a signal whose elements are combinations of the
+    /// receiver elements with the latest elements from the `other` signal.
+    ///
+    /// Check out interactive example: [https://rxmarbles.com/#withLatestFrom](https://rxmarbles.com/#withLatestFrom)
+    public func with<O: SignalProtocol, U>(latestFrom other: O, combine: @escaping (Element, O.Element) -> U) -> Signal<U, Error> where O.Error == Error {
+        return Signal { observer in
+            var latest: O.Element? = nil
+            let compositeDisposable = CompositeDisposable()
+            compositeDisposable += other.observe { event in
+                switch event {
+                case .next(let element):
+                    latest = element
+                case .failed(let error):
+                    observer.failed(error)
+                case .completed:
+                    break
+                }
+            }
+            compositeDisposable += self.observe { event in
+                switch event {
+                case .completed:
+                    observer.completed()
+                case .failed(let error):
+                    observer.failed(error)
+                case .next(let element):
+                    if let latest = latest {
+                        observer.next(combine(element, latest))
+                    }
+                }
+            }
+            return compositeDisposable
+        }
+    }
+
+    /// Combine the receiver and the `other` signal into a signal whose elements are combinations of the
+    /// receiver elements with the latest elements from the `other` signal.
+    ///
+    /// Check out interactive example: [https://rxmarbles.com/#withLatestFrom](https://rxmarbles.com/#withLatestFrom)
+    public func with<O: SignalProtocol>(latestFrom other: O) -> Signal<(Element, O.Element), Error> where O.Error == Error {
+        return with(latestFrom: other, combine: { ($0, $1) })
+    }
+
+    /// Zip elements from the receiver and the `other` signal.
+    /// Zip differs from `combineLatest` in that the combinations are produced from elements at same positions.
+    ///
+    /// Check out interactive example: [https://rxmarbles.com/#zip](https://rxmarbles.com/#zip)
     public func zip<O: SignalProtocol, U>(with other: O, combine: @escaping (Element, O.Element) -> U) -> Signal<U, Error> where O.Error == Error {
         return Signal { observer in
             let lock = NSRecursiveLock(name: "reactive_kit.zip")

        }
    }

    /// Emit a pair of latest elements from each signal. Starts when both signals emit at least one element,
    /// and emits `.next` when either signal generates an element.
    public func combineLatest<O: SignalProtocol>(with other: O) -> Signal<(Element, O.Element), Error> where O.Error == Error {
        return combineLatest(with: other, combine: { ($0, $1) })
    }

    /// First emit events from source and then from `other` signal.
    public func concat(with other: Signal<Element, Error>) -> Signal<Element, Error> {
        return Signal { observer in
            let serialDisposable = SerialDisposable(otherDisposable: nil)
            serialDisposable.otherDisposable = self.observe { event in

        }
    }

    /// Merge emissions from both the receiver and the `other` signal into one signal.
    ///
    /// Check out interactive example: [https://rxmarbles.com/#merge](https://rxmarbles.com/#merge)
    public func merge<O: SignalProtocol>(with other: O) -> Signal<Element, Error> where O.Element == Element, O.Error == Error {
        return Signal(sequence: [self.toSignal(), other.toSignal()]).merge()
    }
