Quicksort: Perhaps the most important algorithm. I managed to write it using a single pattern-matching, and two recursive calls. So it’s not tail-recursive, but shouldn’t be a problem. It’s interesting to note that the algorithm actually sweeps the input only once, with multiple streams in the nested calls taking care of the re-ordering. There would be no intermediary results stored if I could use some kind of Iterator instead of Stream. I don’t know why Scala doesn’t have an Iterator type that I can use in pattern-matching, I hope I just didn’t learn about it yet.

The use of “partition” is probably the most interesting thing about this implementation. It avoids the separate declaration of two different Streams filtering the input twice, instead creating the two necessary sub-lists in a single sweep. (Or at least it looks like that.)

Insertion sort: Perhaps the most important of the inefficient sorting algorithms. I used two tail-recursive functions here, one of them takes care of “inserting” a value in a list at the right place. The higher function just picks the values from the input and “insert” them at the output list one at a time, starting with an empty list. Tail recursion is important here because the number of calls is proportional to the size of the list, and not log(N) like in Quicksort.

Merge-sort: For this I used two tail-recursive functions, and a couple of stream-processing ones. The lowest-level function merges two lists picking the smallest elements first. It’s the fundamental operation from merge-sort. Two other functions are responsible for splitting an input list it in sub-lists with the specified chunk size, and returning them in pairs. It iterates on the input creating an iterator of iterator pairs… It’s pretty complicated, but it’s exactly what we need in merge-sort. The final, most external function is the one that calls the merger function to the sublist pairs, and them join them together as the input for a recursive call, with the sublist size increasing according to the necessary rule, double the size at each iteration. This function doesn’t have to be tail-recursive, but it came out like that naturally.

That was fun! I think I managed to really explore the “functional thinking”, and learn a thing or two about Scala. But I’m still a bit confused about when I should use Lists, Streams or something else. But I definitely think it’s way cooler than writing a procedural in-place Quicksort or insertion sort, for instance, where we having to take care of element indices and stuff, and be constantly afraid of overwriting something I shouldn’t, etc. I also think that even if I could try to write code like this in Python, for instance, it wouldn’t look that cool. The pattern matching is probably the main reason for that.