将命令性功能转变为更具功能性

时间:2018-08-09 13:27:52

标签: scala functional-programming

我在这里找到这个人

      var time = createdAt
      var coolDown = duration
      while (time <= timestamp) {
        if (time <= timestamp && timestamp <= time + timeLimit.getOrElse(0L)) {
          return None
        } else {
          time = time + timeLimit.getOrElse(0L) + coolDown
          coolDown = 2 * coolDown
        }
      }
      Some("Error")

,并希望将其重构为比命令式功能更强大的功能,但是我在函数式编程方面还很陌生,我想知道您实现该功能的方法。我用单元测试进行了介绍,并打算创建一个数学函数或具有一个递归函数。有没有逐步进行的方法?从头开始?您将如何解决?

该函数应返回以下内容:

-N-|-C-|-N-|--C(2x)--|-N-|----C(4x)----|-N-|--------C(8x)---------|-N-|...

返回Error的时间呈指数增长。假设coolDowntimeLimit分别是第一天返回None,第二天Error,第三天None的一天,然后是第二天Error的天数,依此类推...

2 个答案:

答案 0 :(得分:1)

是的,在@Carcigenicate发表评论后,这很容易。我已经开始逐步进行重写,并且方向一致。结果:

def evaluateCooldown(time: Long, coolDown: Long): Option[String] = {
  if (time <= timestamp) {
    if (timestamp <= time + timeLimit.getOrElse(0L)) {
      None
    } else {
      evaluateCooldown(time + timeLimit.getOrElse(0L) + coolDown, 2 * coolDown)
    }
  } else {
    Some("Error")
  }
}
evaluateCooldown(unlockedAt, cdc.duration)

答案 1 :(得分:1)

自然地,有很多方法可以做到这一点。这是使用惰性ADT的一种...

我们定义val ts = timestamp.getOrElse(0L)

def slen(n: Int) = math.pow(2, n - 1) * countDown + timeLimit
val prev = Stream.iterate(1)(slen).scan(0)(_ + _).takeWhile(_ < ts).last

查找时间戳之前的最后一个N | C节的列表长度,然后

if (prev + timeLimit > ts) None else Some("Error")

另一种优化方法

我们可以使用

用累积金额替换scan

def clen(n: Int) = (math.pow(2, n) - 1) * countDown + n * timeLimit
val nextn = Stream.from(1).find(clen(_) > ts)

找到时间戳后第一部分的索引,然后

if (len(nextn - 1) + timeLimit > ts) None else Some("Error")