人們常?粗掌貞浧饛那,清晰地感覺到童年,青年,中年,老年一路走來的各種變化。從這種變化中,我們可以抽象出3個(gè)關(guān)鍵詞:對象、時(shí)間和狀態(tài)。對象擁有狀態(tài)和標(biāo)識,在標(biāo)識不變的情況下,狀態(tài)隨時(shí)間發(fā)展演變。這實(shí)際上代表了一種動態(tài)的世界觀:時(shí)間本身并不屬于世界,世界是在時(shí)間維度上不斷演變的狀態(tài)。在這種世界觀的指導(dǎo)下,通過計(jì)算機(jī)程序模擬現(xiàn)實(shí)世界問題時(shí),我們用計(jì)算機(jī)中的對象狀態(tài)表示世界的狀態(tài),用計(jì)算機(jī)中對象的狀態(tài)的變化表示世界狀態(tài)的變化和時(shí)間進(jìn)程。
與上面動態(tài)的世界觀不同,另一種世界觀認(rèn)為世界本質(zhì)上是靜止的。怎么理解呢?比如:對于一個(gè)歷史人物,在他生活的每一天里都有變化,從這個(gè)角度看是狀態(tài)的變化;但是如果縱觀他的一生,其人生軌跡作為一個(gè)整體又是靜止的,我們可以把這個(gè)整體作為一個(gè)研究的對象。這里,我們實(shí)際上把時(shí)間維度也納入對象屬性,使在3維中運(yùn)動的對象變成了在4維中靜止的對象。物理學(xué)上稱對象在4維空間中的軌跡為對象的世界線(World Line)。另外,即使不是已經(jīng)蓋棺定論的對象,假如對象是有規(guī)律的,比如:一個(gè)物體的運(yùn)動狀態(tài)由某一個(gè)公式完全決定,即未來某一時(shí)刻它處于什么位置也是完全確定的,那么我們只要掌握了這個(gè)公式就掌握了物體的世界線。
我們把對象的世界線用x(t)來表示,如果時(shí)間是離散的,我們可以用一個(gè)序列(Sequence)來表示x(t)。與計(jì)算的對象模型通過狀態(tài)改變來隱式地表示時(shí)間不同,我們可以把計(jì)算認(rèn)為是輸入序列input(t)到輸出序列output(t)的變換,時(shí)間是通過離散序列的方式顯式表示的。我們的程序?qū)嶋H上扮演了一個(gè)信號處理器的角色。
但有限序列的缺點(diǎn)在于它要求輸入是完整的,因而無法處理交互的情況,比如:我們把用戶的鍵盤輸入input(t)無法用一個(gè)有限序列來表示。為了處理交互,我們引入了可用惰性求值的流(Stream)。流可用視為可用惰性求值的無窮序列,這樣我們的程序就是一個(gè)信號處理器,輸入時(shí)一個(gè)流,輸出也是一個(gè)流。為了幫助理解,下面我們用一個(gè)C#實(shí)現(xiàn)的Stack的例子來說明:
//C#實(shí)現(xiàn)的基于流的Stack
public enum OperationType { PUSH, POP}
public struct Input{
public OperationType Operation;
public int Data;
}
class Stack
{
public static IEnumerable<int> Transform(IEnumerable<Input> aSourceStream)
{
LinkedList<int> list = new LinkedList<int>();
foreach(Input command in aSourceStream)
{
if(OperationType.PUSH== command.Operation)
{
list.AddLast(command.Data);
}
else if (OperationType.POP == command.Operation)
{
int data = list.Last.Value;
list.RemoveLast();
yield return data;
}
}
}
}
public class InputGenerator
{
public static IEnumerable<Input> Generate()
{
while (true)
{
string line = Console.ReadLine();
if (line.StartsWith("push "))
{
yield return new Input { Operation = OperationType.PUSH, Data = int.Parse(line.Split(' ')[1]) };
}
else if (line == "pop")
{
yield return new Input { Operation = OperationType.POP };
}
}
}
}
public static void Main(string[] args)
{
foreach (int output in Stack.Transform(InputGenerator.Generate()))
{
Console.WriteLine(output);
}
}
運(yùn)行示例:
>>push 1
>>push 2
>>pop
2
>>push 3
>>pop
3
上面的例子中用戶的輸入被包裝成無窮的Input輸入流,Stack是從Input輸入流到int輸出流的信號處理器。