2009年10月11日 星期日

Macro 的不可或缺

原本我的遊戲是以 javascript 寫成。在研讀過 PLT Scheme手冊後,我開始以 scheme 改寫我的遊戲軟體。 這樣做的原因主要是我欣賞 PLT scheme 中提供的 @-exp 語法。這語法類似 XML,適合用來描述遊戲的劇本,又和 scheme 完美整合。

將劇本以 @-exp 改寫後,我發現 macro 的重要性。以下是我劇本的一個片段:

@novel["家變"]{
  @room["書房"]{
    @scene["牆壁"]{
      你面對一面白色牆壁。牆壁上有條裂縫。向上直達天花板。
      @next["檢查裂縫" #:scene "裂縫"]
      @next["檢查天花板" #:scene "天花板"]
    }
    @scene["天花板"]
      天花板有點潮溼。
    }
    @scene["裂縫"]{
      裂縫中有隻螞蟻。
    }
  }
}

面對這樣的劇本,有兩種作法:
  1. novel 是 scheme function。此時,因為 room 會比 novel 早執行,因此,在執行 novel 前必須先建造一個名為 current-novel 的物件,或是使用一個 global 的物件,以存放 room 產生的資料。這使得劇本必須做小修改,而撰寫劇本的人,很可能不是一位程式設計師,必須操心這些小修改。
  2. novel 是 scheme macro。由於使用 macro,可以將建造 current-novel 的工作包括在 macro 的設計中,因此,撰寫劇本的人就不必操心這些問題。
我沒想到的是,單單劇本撰寫這樣原本以為簡單的工作,竟然也涉及到 macro 的撰寫,也因此體會了 macro 強大的能力。

在設計劇本的描述語言時,我也感受到 scheme 的 keyword 帶來的好處,以以上的劇本為例,在 next 中我使用了 #:scene 這個 keyword,它使得劇本更容易閱讀。

一個讓我驚訝的事是,我目前感受不到 PLT-Scheme 的 define-struct 的好處。原本我使用 (define-struct novel (name)) 來建立 novel 這結構,但最後我改成如同我原本使用 javascript 的作法,使用 hashtable,同時參考 SICP 的作法 來解決。

沒有留言:

張貼留言