Как сделать этот код более функциональным? - PullRequest
2 голосов
/ 19 февраля 2010

Я новичок в функциональном программировании. Я просто попытался решить следующую проблему:

[ 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 и две изменяемые переменные и сделать этот код более функциональным.

Любая помощь будет принята с благодарностью.

Спасибо. :)

Ответы [ 4 ]

3 голосов
/ 21 февраля 2010

Рахул, как я уже сказал, в Scala нет функции unfold Scalaz есть один, так что я покажу решение с его использованием.Решение ниже просто адаптирует ответ Патрика для использования разворачивания вместо рекурсии.

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))
  }
}
3 голосов
/ 20 февраля 2010

Эта хвостовая рекурсивная функция удаляет два изменяемых переменных и цикл:

3 голосов
/ 20 февраля 2010

Хвостовое рекурсивное решение в 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(remainder,radix) и получить Nil, переданный бесплатно.

2 голосов
/ 20 февраля 2010

Я думаю, что это довольно дорогой способ решения проблемы, но очень интуитивный ИМХО:

scala> Stream.iterate(255)(_ / 10).takeWhile(_ > 0).map(_ % 10).reverse
res6: scala.collection.immutable.Stream[Int] = Stream(2, 5, 5)
...