As far as rolling your own implementation of a purely functional map function, without using any mutable state or built-in List higher-order functions, you've done a great job! Having to reverse the list does seem unnecessary, but it's worth it because prepending to a list is a very efficient operation.
As well as the other methods suggested in the comments, you could make acc a scala.collection.mutable.ListBuffer (which supports efficient append and prepend operations), then converting it to a list when you're done. However, the conversion process isn't a great improvement over reverse.
Otherwise, there are a few minor things you can do to improve your map function:
- By using curried arguments, you can use
map more elegantly.
- Functions that need to be tail-recursive should always be decorated with the
scala.annotation.tailrec attribute. The Scala compiler then knows your intention, and will issue an error if the function cannot be optimized to use tail recursion.
- It's trivial to make this function generic, which will make it far more widely useful.
- It's generally more idiomatic to perform the
reverse operation on the result. It makes no difference for a map operation, but if you were to write a filter operation, for example, then it would be more efficient to reverse the potentially smaller set of filtered elements.
Here's how that would then look:
import scala.annotation.tailrec
def map[A, B](list: List[A])(function: (A) => B): List[B] = {
@tailrec
def loop(rem: List[A], acc: List[B]): List[B] = rem match {
case Nil => acc.reverse
case head :: tail => loop(tail, function(head) :: acc)
}
loop(list, Nil)
}
mapin terms of other functions, likeflatMap,foldLeft,foldRight. But, all of these converge to the previous three cases.