代码之家  ›  专栏  ›  技术社区  ›  dbyrne

最佳功能方法

  •  3
  • dbyrne  · 技术社区  · 14 年前

    我有一些可变的scala代码,我正试图用更实用的风格重写。这是一段相当复杂的代码,所以我正试图将其分块重构。我的第一个想法是:

    def iterate(count:Int,d:MyComplexType) = {
      //Generate next value n
      //Process n causing some side effects
      return iterate(count - 1, n)
    }
    
    iterate(2000000,initialValue)
    

    这对我来说似乎一点都不起作用,因为我的代码中仍然混合着副作用。我的第二个想法是:

    def generateStream(d:MyComplexType):Stream[MyComplexType] = {
      //Generate next value n
      return Stream.cons(n, generateStream(n))
    }
    
    for (n <- generateStream(initialValue).take(2000000)) {
      //process n causing some side effects
    }
    

    对我来说,这似乎是一个更好的解决方案,因为至少我已经从可变值处理代码中分离出了我的函数值生成代码。但是,这样的内存效率要低得多,因为我正在生成一个不需要存储的大列表。

    这给我留下了3个选择:

    1. 编写尾部递归函数,咬紧牙关并重构值处理代码
    2. 使用一个懒惰的列表。这不是内存敏感的应用程序(尽管它对性能敏感)
    3. 想出一个新方法。

    我想我真正想要的是一个延迟评估的序列,我可以在处理完这些值之后丢弃它们。有什么建议吗?

    2 回复  |  直到 14 年前
        1
  •  6
  •   Rex Kerr    14 年前

    记住,性能关键的算法在可变时通常工作得更好。因此,小心过早的去优化!

    在scala 2.8中,您可以使用 Iterator.iterate 创建一个没有存储值的无限序列。但我不确定,只有这一步才能使代码重构更具功能性。“处理有副作用的数据”这一部分很棘手。

    您可以将整个内容放入迭代块中:

    Iterator.iterate(initialState)(x => {
      // create a new state based upon state x
    }).drop(2000000).next
    

    现在,您已经通过顺序修改初始状态定义了无限处理流。您丢弃前2000000个值(其中一个是初始值),然后得到下一个值(即2000000的生成值)。用0和x=>x+1试试看它的效果。

        2
  •  3
  •   sblundy    14 年前

    我想你想用 Range 如果你所做的只是创建一个从0到2000000的整数序列。它又好又懒,至少2.7分。