# 惰性计算，第 2 部分

## 构建惰性列表

`{-> [] }`

`{-> [ a, {-> [] } ] }`

`{-> [a, {-> [b, {-> [ c, {-> [] } ] } ] } ] }`

##### 清单 1. 在 Groovy 中使用闭包构建惰性列表
```class PLazyList {
private Closure list

private PLazyList(list) {
this.list = list
}

static PLazyList nil() {
new PLazyList({-> []})
}

}

def lst = list.call()
lst ? lst[0] : null
}

def tail() {
def lst = list.call()
lst ? new PLazyList(lst.tail()[0]) : nil()
}

boolean isEmpty() {
list.call() == []
}

def fold(n, acc, f) {
n == 0 || isEmpty() ? acc : tail().fold(n - 1, f.call(acc, head()), f)
}

def foldAll(acc, f) {
isEmpty() ? acc : tail().foldAll(f.call(acc, head()), f)
}

def take(n) {
fold(n, []) {acc, item -> acc << item}
}

def takeAll() {
foldAll([]) {acc, item -> acc << item}
}

def toList() {
takeAll()
}
}```

##### 清单 2. 执行惰性列表
```def lazylist = PLazyList.nil().cons(4).cons(3).cons(2).cons(1)
println(lazylist.takeAll()) //[1, 2, 3, 4]
println(lazylist.foldAll(0, {i, j -> i + j})) // 10
lazylist = PLazyList.nil().cons(1).cons(2).cons(4).cons(8)
println(lazylist.take(2))  //[8, 4]```

## 惰性的好处

##### 清单 3. 在 Groovy 中查找回文
```def isPalindrome(s) {
def sl = s.toLowerCase()
sl == sl.reverse()
}

def findFirstPalindrome(s) {
s.tokenize(' ').find {isPalindrome(it)}
}

s1 = "The quick brown fox jumped over anna the dog";
println(findFirstPalindrome(s1)) // anna

s2 = "Bob went to Harrah and gambled with Otto and Steve"
println(findFirstPalindrome(s2)) // Bob```

##### 清单 4. Clojure 的回文
```(defn palindrome? [s]
(let [sl (.toLowerCase s)]
(= sl (apply str (reverse sl)))))

(defn find-palindromes [s]
(filter #(palindrome? %) (clojure.string/split s #" ")))

(println (find-palindromes "The brown fox jumped over anna."))
; (anna)
(println (find-palindromes "Bob went to Harrah and gambled with Otto"))
; (Bob Harrah Otto)
(println (take 1 (find-palindromes "Bob went to Harrah and gambled with Otto")))
; (Bob)```

```(fn [x]
(palindrome? x))```

Scala 以稍有不同的方式实现了惰性。它没有在默认情况下让一切成为惰性的，而是提供了集合上的惰性视图。请考虑清单 5 中回文问题的 Scala 实现：

##### 清单 5. Scala 回文
```def isPalindrome(x: String) = x == x.reverse
def findPalidrome(s: Seq[String]) = s find isPalindrome

findPalindrome(words take 1000000)```

`findPalindrome(words.view take 1000000)`

`view` 方法允许执行集合的惰性遍历，并支持更高效的代码。

## 惰性字段初始化

`lazy val x = timeConsumingAndOrSizableComputation()`

##### 清单 6. Scala 为惰性字段生成的语法糖
```var _x = None
def x = if (_x.isDefined) _x.get else {
_x = Some(timeConsumingAndOrSizableComputation())
_x.get
}```

Groovy 也有一个类似的工具，它使用了一个称为 Abstract Syntax Tree (AST) Transformations 的高级语言特性。这些特性使您能够与编译器生成的底层抽象语法树进行交互，允许进行低层次的用户转换。其中一个预定义的转换是 `@Lazy` 属性，如清单 7 中的行动所示：

##### 清单 7. Groovy 中的惰性字段
```class Person {
@Lazy pets = ['Cat', 'Dog', 'Bird']
}

def p = new Person()
assert !(p.dump().contains('Cat'))

assert p.pets.size() == 3
assert p.dump().contains('Cat')```

```class Person {
@Lazy List pets = { /* complex computation here */ }()
}```

```class Person {
@Lazy(soft = true) List pets = ['Cat', 'Dog', 'Bird']
}```

## 结束语

#### 相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Java technology
ArticleID=854841
ArticleTitle=函数式思维: 惰性计算，第 2 部分
publish-date=01172013