Not tail recursive implementation


def basename(names:Iterable[String]):Option[String] = {
if (names.exists(_.size==0) || names.size<=1) None
else {
val firsts = names.map(_.head)
if (firsts.toSet.size>1) None
else {
Some(firsts.head.toString+basename(names.map(_.tail)).getOrElse(""))
}
}
}

Tail recursive implementation


@annotation.tailrec
def basename(names:Iterable[String], accu:Option[String]=None):Option[String] = {
if (names.exists(_.size==0) || names.size<=1) accu
else {
val firsts = names.map(_.head)
if (firsts.toSet.size>1) accu
else basename(names.map(_.tail), Some(accu.getOrElse("")+firsts.head))
}
}

Usage example


$ scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :paste
// Entering paste mode (ctrl-D to finish)

@annotation.tailrec
def basename(names:Iterable[String], accu:Option[String]=None):Option[String] = {
if (names.exists(_.size==0) || names.size<=1) accu
else {
val firsts = names.map(_.head)
if (firsts.toSet.size>1) accu
else basename(names.map(_.tail), Some(accu.getOrElse("")+firsts.head))
}
}

// Exiting paste mode, now interpreting.

basename: (names: Iterable[String], accu: Option[String])Option[String]

scala> basename(List("trucmuche", "trucmoche", "trucduq"))
res0: Option[String] = Some(truc)

scala> basename(List("was1", "was2"))
res1: Option[String] = Some(was)

scala> basename(List("was1"))
res2: Option[String] = None

Of course if we annotate with @tailrec the not tail recursive implementation we got the following error :

scala> :paste
// Entering paste mode (ctrl-D to finish)

@annotation.tailrec
def basename(names:Iterable[String]):Option[String] = {
if (names.exists(_.size==0) || names.size<=1) None
else {
val firsts = names.map(_.head)
if (firsts.toSet.size>1) None
else {
Some(firsts.head.toString+basename(names.map(_.tail)).getOrElse(""))
}
}
}

// Exiting paste mode, now interpreting.

:15: error: could not optimize @tailrec annotated method basename: it contains a recursive call not in tail position
Some(firsts.head.toString+basename(names.map(_.tail)).getOrElse(""))