如何在OOP语言中实现按需惰性求值,以使其符合函数式编程范式?

时间:2015-07-06 13:03:52

标签: scala functional-programming lazy-evaluation

我在从OOP思维转向功能性思维方面遇到了一些麻烦。我目前的问题是我有一个不可变的,持久的数据结构,可以用它(比方说)来构建URL-s:

class UrlBuilder {

  public UrlBuilder withHost(String domain) {
    return new UrlBuilder(/*...*/);
  }

  public UrlBuilder withPort(Int port) {
    return new UrlBuilder(/*...*/);
  }

  // ...

  public String build() {
    // ...
  }
}

懒惰地评估字符串的build()方法非常昂贵,所以我想缓存结果。

在OOP中这没问题,因为我可以这样做:

class UrlBuilder {
  private String url;

  // ...

  public String build() {
    if (null == this.url) {
      this.url = doExpensiveEvaluation();
    }
    return this.url;
  }
}

如果我需要线程安全,我会使用双重检查锁定并完成它。但据我所知,这是反对功能范式,因为它引入了副作用(修改了对象的内部状态)。

我知道在Scala中有lazy关键字,它完全符合我的需要:实现所谓的 by-need 懒惰。但是我怎样才能用OOP语言做同样的事情呢?我实际上非常好奇他们如何在Scala中实现它。

我试图将结果缓存到我的UrlBuilder的消费者的责任,但这在消费者方面引起了同样的问题:

class Consumer {
  private UrlBuilder urlBuilder;
  private String url;
  // ...
  public String getUrl() {
    if (null == this.url) {
      this.url = urlBuilder.build(); // same as before!
    }
    return this.url;
  }
}

因此我在标题中提出了问题。

编辑:要明确:我问的是除了Scala以外的OOP语言实现。它可能是Java或C#,但我也想知道如何在JavaScript之类的东西中做到这一点。正如我所提到的,我可以使用锁定,但我一直在寻找一种纯功能解决方案,而不必使用锁定。

我的印象是功能编程是开箱即用的线程安全,因此锁定感觉就像一个丑陋的OOP解决方案。但当然我也会接受一个证明这是不可能的答案。 Ben Reich的The comment bellow几乎说明了一切:如果Scala开发人员在没有锁定的情况下无法做到这一点,那么我可能会死于尝试。

3 个答案:

答案 0 :(得分:1)

我们在谈论java不是吗?为什么不同步呢?

class LazyClass 
{

    Integer someValue = null;
    public synchronized Integer someReallyExpensiveMethod() {
        if (someValue == null)
        {
            someValue = 1 + 2 + 3; // .. + 32 + .. this takes a long time
        }
        return someValue;
    }

}

答案 1 :(得分:0)

这个怎么样:

object UrlBuilder{
    def empty = new InnerBuilder("")

    class InnerBuilder(...){
        def withHost(host: String) = new InnerBuilder(...)
        def withPort(port: Int) = new InnerBuilder(...)
        def build(): String = ...
    }
这样你就没有任何可变的状态     }

并使用它:

UrlBuilder.empty
          .withHost(...)
          .withPort(...)
          .build()

答案 2 :(得分:0)

我已经找到了Rich Hickey对这个问题in this article的最佳答案。它涉及所谓的瞬态数据结构的Closure实现。它们本质上是对持久数据结构的可变副本进行操作,但是对于外部世界透明地执行(在后台使用锁定)。

除了描述数据结构如何工作之外,文章基本上表明只要无法观察到突变就可以进行突变。

事实证明这是某种哲学问题。文章的引用总结了这个非常好的:

  

如果一棵树落在树林里,它会发出声音吗?

     

如果纯函数改变某些本地数据以产生不可变的返回值,那可以吗?

     

- Rich Hickey,Clojure