这是Scala中的纯函数吗?

时间:2014-12-19 15:27:51

标签: scala functional-programming

在函数getRandomString下面,从字符列表中生成一个随机字符串:

  def genRandomInt(lb: Int, ub: Int) = {
    val rnd = new scala.util.Random
    lb + rnd.nextInt(ub)
  }     
  def getRandomString(validChars: List[Char]) = {

    val size = validChars.size

    val random = new scala.util.Random
    val stringBuilder = new StringBuilder
    val rnd = genRandomInt(0, size)
    val sb = new StringBuilder

    for (i <- 0 to size - 1) {
      val rnd = genRandomInt(0, size)
      sb.append(validChars(rnd))
    }

    sb.toString
  }                                               //> getRandomString: (validChars: List[Char])String

    val rs = getRandomString(('a' to 'j').toList)
                                                  //> rs  : String = aghdjjhjge

getRandomString是纯函数的一个例子,因为它不会修改状态吗?

2 个答案:

答案 0 :(得分:8)

不,因为它实际上确实修改了状态。 new scala.util.Random最终调用new java.util.Random,它访问并修改名为AtomicLong的静态(即全局)可变seedUniquifier。因此,如果多次调用此方法,则结果将发生变化。

这是一个很好的例子,说明无辜的看似方法如何隐藏对全局可变状态的访问,这在Haskell等更严格的函数式语言中是被禁止的(尽管这种方法有其自身的问题)。

答案 1 :(得分:1)

不,因为new scala.util.Random().nextInt ...每次都会返回不同的内容,这是由Imm。

解释的

然而,您可以简单地传入一个种子然后它将是一个纯函数,因为它每次都会返回相同的随机字符串。您可以将种子添加为参数,或者只是将其固定在随机字符串方法中。

最后,我注意到您已经编写了大量代码来生成随机字符串。我建议你看一下ScalaCheck,它有很多有用的函数来生成随机的东西(用于单元测试),String是开箱即用的。

如果您不想加入某个库,您仍然可以使该代码更加简洁:

def randomString(fromChars: List[Char], length: Int): String = {
  val rand = new Random(1234) // Now it's pure functional because the seed is fixed
  val fromCharsSize = fromChars.size // to save us repeatedly counting
  List.fill(length)(fromChars(rand.nextInt(fromCharsSize))).mkString
}

观察它每次返回相同的值

scala> randomString("asdf".toList, 10)
res0: String = dsfafssdsa

scala> randomString("asdf".toList, 10)
res1: String = dsfafssdsa