At the time that I'm writing this answer, I don't think that any of the other answers faithfully replicate Haskell's span function. That's okay, you may actually be looking for something else, but I wanted to add this for completion's sake.
First, you can't necessarily assume that span only iterates over the input list once. It's difficult to reason about Haskell's run-time behaviour because of its lazy evaluation, but consider this list:
xs = [trace "one" 1, trace "two" 2, trace "three" 3,
trace "one" 1, trace "two" 2, trace "three" 3]
Here I've deliberately used trace from Debug.Trace so that we can observe what's going on. Specifically, I want to point your attention to what happens if you iterate over the lists independently, as one would probably do in 'real' code:
Prelude Data.List Debug.Trace> (l, r) = span (< 3) xs
Prelude Data.List Debug.Trace> l
one
[1two
,2three
]
Iterating over the first list stops at the first value that evaluates to False, so that's fine and efficient. That's not the case, however, when you print the second list:
Prelude Data.List Debug.Trace> r
one
two
three
[3,one
1,two
2,three
3]
Notice that while it only prints [3, 1, 2, 3], it iterates over the entire list. How could it do otherwise? It's a function. It doesn't maintain a bookmark over how far it's already iterated the list.
On the other hand, the function does handle infinite lists:
Prelude Data.List> take 10 $ fst $ span (< 3) $ repeat 1
[1,1,1,1,1,1,1,1,1,1]
Prelude Data.List> take 10 $ fst $ span (< 3) $ repeat 3
[]
Prelude Data.List> take 10 $ snd $ span (< 3) $ repeat 3
[3,3,3,3,3,3,3,3,3,3]
As far as I can tell, few of the other answers (as I'm writing this) handle infinite lists.
In C#, lazily evaluated lists are modelled with IEnumerable<T>, so the best I've been able to come up with is this:
public static (IEnumerable<T>, IEnumerable<T>) Span<T>(
this IEnumerable<T> source,
Func<T, bool> pred)
{
return (source.TakeWhile(pred), source.SkipWhile(pred));
}
which, admittedly, is hardly above the Fairbairn threshold. It does, however, handle infinite sequences in the same way as span does:
> var (left, right) = new[] { 1, 2, 3, 1, 2, 3 }.Span(x => x < 3);
> left
TakeWhileIterator { 1, 2 }
> right
SkipWhileIterator { 3, 1, 2, 3 }
> var (left, right) = 1.RepeatInfinite().Span(x => x < 3);
> left.Take(10)
TakeIterator { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
> var (left, right) = 3.RepeatInfinite().Span(x => x < 3);
> right.Take(10)
TakeIterator { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }
> left.Take(10)
TakeIterator { }