 ///
 /// Returns a producer that will send values from `producer`, sampled (possibly
 /// multiple times) by `sampler`, then complete once both inputs have completed.
-public func sampleOn<T, E>(sampler: SignalProducer<(), NoError>)(producer: SignalProducer<T, E>) -> SignalProducer<T, E> {
-	return producer.lift(sampleOn)(sampler)
+public func sampleOn<T, E>(sampler: SignalProducer<(), NoError>) -> SignalProducer<T, E> -> SignalProducer<T, E> {
+	return { producer in
+		return producer.lift(sampleOn)(sampler)
+	}
 }
 
 /// Forwards events from `producer` until `trigger` sends a Next or Completed
 /// event, at which point the returned producer will complete.
-public func takeUntil<T, E>(trigger: SignalProducer<(), NoError>)(producer: SignalProducer<T, E>) -> SignalProducer<T, E> {
-	return producer.lift(takeUntil)(trigger)
+public func takeUntil<T, E>(trigger: SignalProducer<(), NoError>) -> SignalProducer<T, E> -> SignalProducer<T, E> {
+	return { producer in
+		return producer.lift(takeUntil)(trigger)
+	}
 }
 
 /// Forwards events from `producer` until `replacement` begins sending events.

}

/// `concat`s `next` onto `producer`.
public func concat<T, E>(next: SignalProducer<T, E>)(producer: SignalProducer<T, E>) -> SignalProducer<T, E> {
	return SignalProducer(values: [producer, next]) |> flatten(.Concat)
}

/// Repeats `producer` a total of `count` times.
/// Repeating `1` times results in a equivalent signal producer.
public func times<T, E>(count: Int)(producer: SignalProducer<T, E>) -> SignalProducer<T, E> {
	precondition(count >= 0)

	if count == 0 {
		return .empty
	} else if count == 1 {
		return producer
	}

	return SignalProducer { observer, disposable in
		let serialDisposable = SerialDisposable()
		disposable.addDisposable(serialDisposable)

		let iterate: Int -> () = fix { recur in
			{ current in
				producer.startWithSignal { signal, signalDisposable in
					serialDisposable.innerDisposable = signalDisposable

					signal.observe(Signal.Observer { event in
						switch event {
						case .Completed:
							let remainingTimes = current - 1
							if remainingTimes > 0 {
								recur(remainingTimes)
							} else {
								sendCompleted(observer)
							}

						default:
							observer.put(event)
						}
					})
				}
			}
		}

		iterate(count)
	}
}

/// Ignores errors up to `count` times.
public func retry<T, E>(count: Int)(producer: SignalProducer<T, E>) -> SignalProducer<T, E> {
	precondition(count >= 0)

	if count == 0 {
		return producer
	} else {
		return producer |> catch { _ in
			producer |> retry(count - 1)
		}
	}
}

///
/// Signals started by the returned producer will not send a value until both
/// inputs have sent at least one value each.
public func combineLatestWith<T, U, E>(otherSignalProducer: SignalProducer<U, E>) -> SignalProducer<T, E> -> SignalProducer<(T, U), E> {
	return { producer in
		return producer.lift(combineLatestWith)(otherSignalProducer)
	}
}

internal func combineLatestWith<T, E>(otherSignalProducer: SignalProducer<T, E>) -> SignalProducer<[T], E> -> SignalProducer<[T], E> {
	return { producer in
		return producer.lift(combineLatestWith)(otherSignalProducer)
	}
}

/// Zips elements of two signal producers into pairs. The elements of any Nth
/// pair are the Nth elements of the two input producers.
public func zipWith<T, U, E>(otherSignalProducer: SignalProducer<U, E>) -> SignalProducer<T, E> -> SignalProducer<(T, U), E> {
	return { producer in
		return producer.lift(zipWith)(otherSignalProducer)
	}
}

internal func zipWith<T, E>(otherSignalProducer: SignalProducer<T, E>) -> SignalProducer<[T], E> -> SignalProducer<[T], E> {
	return { producer in
		return producer.lift(zipWith)(otherSignalProducer)
	}
}

/// Combines the values of all the given producers, in the manner described by
