Yes. Let's say sort here is quicksort (a reasonable choice). Quicksort works, as you know, by partitioning based on a pivot element, putting those smaller before the pivot and those larger after the pivot. It then recursively sorts the two partitions. In Haskell this recursive sort is deferred until the result is actually needed, and a smart haskeller implementing the quicksort would choose to do the smaller-than-pivot partition first--as is the default syntactic choice in any case when concatenating two lists. On each recursion the smaller-than-pivot branch is taken and the larger-than-pivot branch is deferred. As soon as condition is hit where the pivot is the smallest element, it is immediately returned to `take`. The `take` implementation then calls for another value if k>1, and it resumes from where it left of, recursing into the previously deferred larger-than-pivot partition at the bottom of the execution tree, and working itself up from there until `take` is satisfied. Once `k` elements are taken, there's still a partial tree of unexecuted continuations that is thrown away.
In other words, the very nature of Haskell's lazy-by-default semantics makes the straight-forward, seemingly strict implementation of quicksort, or other sorting algorithm, automatically optimized to improve performance through lazy execution.