“Lisp as an Alternative to Java”のお題を Scalaで

“Lisp as an Alternative to Java”のお題を Squeak Smalltalk で - Smalltalkのtは小文字です経由
scala勉強中に付き、上記サイトで面白い問題を発見したので早速やってみました。思ったより時間がかかったけど関数脳の良いトレーニングになった気がする。問題の詳細はリンク先をご覧下さい。

object Phone extends Application {
  val map = List("e","jnq","rwx","dsy","ft","am","civ","bku","lop","ghz");
  val dictionary = List("an","blau","Bo\"","Boot","bo\"s","da","Fee","fern","Fest","fort",
                        "je","jemand","mir","Mix","Mixer","Name","neu","o\"d","Ort","so","Tor","Torf","Wasser");
  val phones = List("112","5624-82","4824","0721/608-4067","10/783--5","1078-913-5","381482","04824");

  case class DD(word:String,digits:Seq[Int]) extends (String,Seq[Int])(word,digits) {
    def isDigit = word.first.isDigit
    override def toString = word.toString
  }
  
  val digiDict = dictionary.map( w => DD(w,digitsWord(w)) )
  def digits(in: String): Seq[Int] = in.filter(_.isDigit).map(_.asDigit)
  def digitFromLetter(in: Char): Int = map.findIndexOf(_.contains(in.toLowerCase))
  def digitsWord(word: String): Seq[Int] = word.map(digitFromLetter(_)).filter(_ != -1)

  def matchDigiDict(digits: Seq[Int]): Seq[DD]= {
    digiDict.filter( dd => digits.startsWith(dd.digits) ) match {
      case Nil => DD(digits.first.toString,digits.first::Nil)::Nil
      case x => x
    }
  }
  
  def patterns(digits: Seq[Int]): Seq[ Seq[DD] ] = digits.length match {
    case 0 => Nil::Nil
    case _ => matchDigiDict(digits).flatMap(
      dd => patterns(digits.drop(dd.digits.length))
        .filter(node=> !(dd.isDigit && node.length>=1 && node.first.isDigit) ) 
        .map(node=> dd::Nil++node))
  }

  phones.map( p => println( p + " => " + patterns(digits(p))))
}

出力

112 => List()
5624-82 => List(List(mir, Tor), List(Mix, Tor))
4824 => List(List(fort), List(Tor, 4), List(Torf))
0721/608-4067 => List()
10/783--5 => List(List(je, Bo", da), List(je, bo"s, 5), List(neu, o"d, 5))
1078-913-5 => List()
381482 => List(List(so, 1, Tor))
04824 => List(List(0, fort), List(0, Tor, 4), List(0, Torf))