Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何使此代码更具功能性?_Scala_Refactoring_Functional Programming - Fatal编程技术网

Scala 如何使此代码更具功能性?

Scala 如何使此代码更具功能性?,scala,refactoring,functional-programming,Scala,Refactoring,Functional Programming,我是函数式编程的新手。我只是尝试解决以下问题: [ a rough specification ] e.g.1: dividend : {3,5,9} divisor : {2,2} radix = 10 ans (remainder) : {7} Procedure : dividend = 3*10^2+5*10^1+9*10^0 = 359 similarly, divisor = 22 so 359 % 22 = 7 e.g.2: dividend : {555,555,555,5

我是函数式编程的新手。我只是尝试解决以下问题:

[ a rough specification ]

e.g.1:
dividend : {3,5,9}
divisor : {2,2}
radix = 10
ans (remainder) : {7}

Procedure :
dividend = 3*10^2+5*10^1+9*10^0 = 359
similarly, divisor = 22
so 359 % 22 = 7

e.g.2:
dividend : {555,555,555,555,555,555,555,555,555,555}
divisor: {112,112,112,112,112,112,112,112,112,112}
radix = 1000
ans (remainder) : {107,107,107,107,107,107,107,107,107,107}
我对这个问题的解决办法是:

object Tornedo {
  def main(args: Array[String]) {
    val radix: BigInt = 1000
    def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
    val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
    val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
    var remainder = dividend % divisor
    var rem = List[BigInt]()
    while(remainder > 0) {
      rem = (remainder % radix) :: rem
      remainder /= radix
    }
    println(rem)
  }
}
虽然我对这段代码非常满意,但我想知道如何消除while循环&两个可变变量,使这段代码更具功能性

任何帮助都将不胜感激


谢谢。:)

Scala 2.8中的尾部递归解决方案:

def reradix(value: BigInt, radix: BigInt, digits:List[BigInt] = Nil): List[BigInt] = {
  if (remainder==0) digits
  else reradix(value/radix ,radix ,(value % radix) :: digits)
}
这个想法通常是将一段时间转换为递归解决方案,在这个过程中跟踪解决方案(因此它可以是尾部递归的,就像这里一样)。如果你用

(value % radix) :: reradix(value/radix, radix)

您还可以计算解决方案,但它不是尾部递归的,因此部分答案将被推到堆栈上。对于默认参数,添加一个允许您存储累积答案并使用尾部递归的最终参数在语法上是很好的,因为您可以调用
reradix(余数,基数)
,并免费获得
Nil

此尾部递归函数删除两个可变变量和循环:

object Tornedo {
  def main(args: Array[String]) {
    val radix: BigInt = 1000
    def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
    val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
    val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
    def breakup(n: BigInt, segs: List[BigInt]): List[BigInt] = 
      if (n == 0) segs else breakup(n / radix, n % radix :: segs)
    println(breakup(dividend % divisor, Nil))
  }
}

我认为这是一种非常昂贵的解决问题的方法,但非常直观:

scala> Stream.iterate(255)(_ / 10).takeWhile(_ > 0).map(_ % 10).reverse
res6: scala.collection.immutable.Stream[Int] = Stream(2, 5, 5)
Rahul,正如我所说,Scala中没有
展开
函数。里面有一个,所以我要用这个来展示解决方案。下面的解决方案只是简单地适应使用展开而不是递归

import scalaz.Scalaz._

object Tornedo {
  def main(args: Array[String]) {
    val radix: BigInt = 1000
    def buildNum(segs: BigInt*) = (BigInt(0) /: segs.toList) { _ * radix + _ }
    val dividend = buildNum(555,555,555,555,555,555,555,555,555,555)
    val divisor = buildNum(112,112,112,112,112,112,112,112,112,112)
    val unfoldingFunction = (n: BigInt) => 
      if (n == 0) None else Some((n % radix, n / radix))
    println((dividend % divisor).unfold[List, BigInt](unfoldingFunction))
  }
}

我不熟悉scala,因此无法调整您的代码。为了更接近函数式,while循环可能应该转换为尾部递归函数。当然,如果scala没有尾部调用优化,那么这个解决方案是有争议的。它可以用
unfold
函数来解决,但scala没有。也许Scalaz会。@Daniel:你能在这里发布这个解决方案吗?+1,但你不需要为递归函数指定结果类型吗?+1,哇!这个
展开
似乎是一个非常有用的函数。我想知道为什么标准库不提供它。@Rahul几乎所有的Scalaz都非常有用,但它也非常抽象,非常关注正确性。它非常倾向于Haskell,我认为,这就是此类函数无法进入Scala std库的原因。Odersky非常担心Scala对新手来说并不令人畏惧和陌生,如果Scala代码经常使用Scalaz中的类似代码,它肯定会有这种感觉。老实说,如果您不知道该代码应该做什么,那么如果您之前不了解unfold,您理解它有多容易?不,可能不知道。但是像
foldLeft
flatMap
这样的函数也是如此。直到我真正研究了它们,我才知道它们是干什么的。@Rahul,好吧,这不是一条明确定义的线——它甚至不是一个明确定义的主题我自己也经常抱怨标准库中缺少
explode
。尽管如此,如果你喜欢它,那么你应该关注Scalaz。这是最起码的。