如何重写此Scala程序以使其更具功能性?

时间:2015-06-01 13:24:23

标签: scala functional-programming purely-functional

我正在解决一个类似的编程练习:

  

文件包含正整数和之间的等式列表,每行一个,每个以分号结尾,没有空格。这些平等可能是对的,也可能是错的。例如,请考虑以下文件:

2+3+12=9+8;
2+3+4=9;
22=3+4+5+10;
3+5+1=4+44;
     

编写一个以文件名作为第一个参数的程序,并输出正确行的比例。例如,给定上面的文件,程序应该输出0.75。

我在Scala中的解决方案如下,并且它可以工作,但我正在寻找一种在没有var的情况下重写它的方法。

import scala.io.Source

object Hello {
  def main(args: Array[String]): Unit = {
    var count: Int = 0
    var correct: Int = 0

    Source.fromFile(args(0)).getLines().zipWithIndex.foreach { case (line, i) =>
      val regex = """^[1-9][0-9]*(\+[1-9][0-9]*)*=[1-9][0-9]*(\+[1-9][0-9]*)*;$""".r
      regex findFirstIn line match {
        case Some(_) =>
        case None => throw new Exception("Error reading file, line " + i)
      }
      val sums = line.substring(0, line.length - 1).split('=').map {
        _.split('+').map(Integer.parseInt).sum
      }
      count += 1
      correct += (if (sums(0) == sums(1)) 1 else 0)
    }
    println("The ratio is " + correct.toFloat/count)
  }
}

我试图把那个foreach变成一张地图,就像这样:

import scala.io.Source

object Hello {
  def main(args: Array[String]): Unit = {
    val file = Source.fromFile(args(0))
    val correct = file.getLines().zipWithIndex.map({ case (line, i) =>
      val regex = """^[1-9][0-9]*(\+[1-9][0-9]*)*=[1-9][0-9]*(\+[1-9][0-9]*)*;$""".r
      regex findFirstIn line match {
        case Some(_) =>
        case None => throw new Exception("Error reading file, line " + i)
      }
      val sums = line.substring(0, line.length - 1).split('=').map {
        _.split('+').map(Integer.parseInt).sum
      }
      return if (sums(0) == sums(1)) 1 else 0
    }).sum
    println("The ratio is " + correct/file.getLines().length)
  }
}

编译器抱怨:

Warning:(15, 38) a pure expression does nothing in statement position; you may be omitting necessary parentheses
      return if (sums(0) == sums(1)) 1 else 0
                                     ^
Warning:(15, 45) a pure expression does nothing in statement position; you may be omitting necessary parentheses
      return if (sums(0) == sums(1)) 1 else 0
                                            ^
Warning:(15, 7) enclosing method main has result type Unit: return value discarded
      return if (sums(0) == sums(1)) 1 else 0
      ^
Error:(16, 8) ambiguous implicit values:
 both object BigIntIsIntegral in object Numeric of type scala.math.Numeric.BigIntIsIntegral.type
 and object ShortIsIntegral in object Numeric of type scala.math.Numeric.ShortIsIntegral.type
 match expected type Numeric[B]
    }).sum
       ^
Error:(16, 8) could not find implicit value for parameter num: Numeric[B]
    }).sum
       ^
Error:(16, 8) not enough arguments for method sum: (implicit num: Numeric[B])B.
Unspecified value parameter num.
    }).sum
       ^

1 个答案:

答案 0 :(得分:5)

您可以定义两个案例类来简化您的任务:

case class Equation(left:Sum,right:Sum) {
  // to check if both sides of equation are equal
  def isCorrect = left.sum == right.sum
}
object Equation {
  // a pattern to extract left and right part of the equation
  val equationPattern = "([0-9\\+]+)=([0-9\\+]+);".r
  // apply method for building equation from string
  def apply(line:String) = line match {
    // building new equation, but use Sum for left/right side parsing
    case equationPattern(left,right) => new Equation(Sum(left), Sum(right))
    case _ => throw new IllegalArgumentException("cannot parse equation")
  }
}

Equation类用于解析和分析您的等式,但它使用嵌套的案例类Sum来解析等式的左侧或右侧部分。

case class Sum(elements:List[Int]) {
  // just sum all elements in this equation side
  def sum:Int = elements.sum
}
object Sum {
  // construct Sum from a String like "1+2+3+4"
  def apply(line:String) = new Sum(line.split("\\+").map(_.toInt).toList)
}

使用这些简单的案例类,我们可以轻松地解析和分析像你这样的方程式:

object Main {
  def main(args: Array[String]): Unit = {
    println(Equation("1+2=3+4;").isCorrect) // prints 'false'
    println(Equation("1+2+4=3+4;").isCorrect) // prints 'true'
  }
}