Scheme Script


注意!: Dr. Geo 的作者正在改用 squeak 從頭改寫 Dr. Geo II, 因此未來它的 scripting 語言可能改成 squeak, 而這個單元的講義也極可能不適用於 Dr. Geo II。 注意!

Dr. Geo 不只可以畫圖, 還可以拿來寫 scheme 程式。 別緊張, 不是完整的巨大程式, 只是簡單的程式片段, 像這樣:

        (let*
            (
                (a 3)
                (b 4)
            )
            (sqrt (+ (* a a) (* b b)))
        )

[舊版講義的寫法如下, 也可以; 不過習慣上 define 用於函數與真正的常數; let* 稍微像傳統程式語言變數用法, 但它也不是設定變數, 因為 scheme 基本上是 functional language, 不鼓勵 「變數」 的思考方式。]

        (define x 3)
        (define y 4)
        (sqrt (+ (* x x) (* y y)))

事先兩點提醒: Dr. Geo 的 scheme script 撰寫/除錯環境還不成熟, 如果你寫的 script 出錯, 會一直跳出錯誤訊息視窗, 關再多次也沒有用。 這時只能用橡皮擦把這個 script 擦掉, 重新再來一次。 因此建議把程式寫在自己的 editor 裡面 (例如 vim 或 emacs), 或是乾脆寫在 Dr. Geo 自己提供的文字頁面 ("create a new text"), 這樣寫錯的 script 擦掉以後還可以再剪貼回來。

  1. 選取 「數值」 工具底下的 「命令稿」, 然後在背景點一下, 產生一個空的 scheme script。
  2. 選取 「其他」 工具底下的 「更改物件屬性」, 然後在剛才產生的空白 scheme scrip 上面點一下, 於是跳出一個對話框。
  3. 把上面的程式剪貼進去, 並按確定。 畫布上應該出現 5。

可以猜得出來, 上面的程式用意在計算 sqrt(3*3+4*4) 。 不過它的運算式寫法卻有點奇怪, 採用 prefix notation -- 也就是把運算符號 (運算子 operator) 寫在前面; 數字 (運算元 operand) 寫在後面。

兩向量所張開平行四邊形的有向面積 當然, 一個計算固定數字的 script 沒什麼好玩。 Dr. Geo 的 scheme script, 還可以接受參數, 算出來的值可以跟隨著圖上點線的位置大小改變。 暫時先不管 scheme 的語法, 我們先用 有向面積 (signed area) (或稱圍積 wedge) 為例, 學會如何製作 script。 兩個向量 (x1,y1) 與 (x2,y2) 張開一個平行四邊形, 它的有向面積是 x1*y2 - x2*y1。 這個簡單的公式可用於計算 (可凹可凸) 不規則多邊形的面積與重心, 或是力矩。

        (let*
            (
                (v1 (getCoordinates a1))
                (v2 (getCoordinates a2))
            )
            (- (* (car v1) (cadr v2)) (* (cadr v1) (car v2)))
        )
  1. 畫兩個共用起點的向量, 分別叫它們 u 與 v 好了。
  2. 選取 「數值」 工具底下的 「命令稿」, 然後先在 u 點一下, 再在 v 點一下, 最後在背景點一下, 產生一個空的 scheme script。
  3. 一樣, 用 「更改物件屬性」 功能叫出編輯視窗, 把上面的程式貼進去。
  4. 拉動兩向量, 觀看這個數值的變化。 從 u 到 v 如果是逆時針旋轉, 算出來的就是正數; 如果是順時針旋轉, 算出來的就是負數; 如果兩向量共線 (同向或反向), 答案就接近 0。

scheme 語言初探

Scheme 是 lisp 類語言當中的一種方言 (dialect)。 Dr Geo 所採用的就是 scheme 方言的一個實作, 叫做 guile。 (就像 "文書處理軟體" 有很多類, 其中有一類是 「所見即所得的文書處理軟體」, OpenOffice.org 就是此類軟體的一個實作。) 如果您對這個語言有興趣, 請安裝 guile 套件, 並建一個文字檔叫做 ~/.guile 裡面放

        (use-modules (ice-9 readline))
        (activate-readline)
    

這樣才可以用 readline 提供的便利快速鍵。 在命令列底下打 guile 進入。 試幾個簡單的指令:

(define pi 3.1416)      # 定義常數
pi                      # 查看 pi 的值
(set! pi 3)             # 改變常數的值; 程式中建議避免使用
(set! pi (+ (* 3 3) (* 4 4)))   # 遇到複雜算式, 由內往外算
(set! pi '(+ (* 3 3) (* 4 4)))  # ' 阻止計算, 把後面當做資料
(car pi)                # 取得 list 的頭
(cdr pi)                # 取得 list 的身體 (扣除頭之外所有部分)
(car (cdr pi))          # "身體的頭" 印出什麼?
(cadr pi)               # 等同上句效果

如前所述, lisp 語言是 functional language, 所以在程式中建議避免使用 set!, 而應常用 let* ("令" 的意思, 語法如上例)。 又, 從 car, cdr, cadr 的例子中, 可以看出為什麼這個語言叫做 lisp -- 專門用來 process list 的語言。 可以上網找一份 scheme tutorial 來試著照打看看, 例如勤益科大朱孝國老師的 Scheme Note, (網路上英文的 tutorial 超多的)

但其實也並不需要學那麼多。 對 Dr Geo 的愛好者而言, 畫圖可能遠比代數或寫程式有意思。 您只需要知道 let*, car, cdr, cadr 三四個指令, 再查詢一下 guile 文件 看看有沒有你心中想像的數學基本 函數 (例如 sqrt, sin, atan, ... 等等) 可以用, 就幾乎足夠。

剩下唯一的問題是: scheme 怎麼從 Dr. Geo 的圖當中取得資料? 一個 scheme script 如果接受畫面上的幾何物件當做參數, 第一個參數就叫做 a1, 第二個參數叫做 a2, ... 等等。 (彷彿系統已自動幫您 define 或 let* 過了) 這些幾何物件拿來不能直接用, 必須透過一些函數取得它的座標 (coordinates 或 abscissa), 長度 (length 或 norm), ... 等等。 這類與幾何物件有關的函數, 是 Dr. Geo 提供的, 在 guile 手冊裡面找不到。 但是 Dr. Geo 的手冊, 英文不完整且有點過時; 法文版 及其他歐洲語言版比較完整。 沒關係, 可以用 AltaVista 的 babelfish 服務, 翻譯成怪怪的英文版手冊, 湊合著看。 從 contents 可以找到 "methods of reference for script Dr. Geo", 這裡就是幾何函數列表。 所以現在回頭看有向面積的程式應該就沒有問題了。

Dr. Geo 的 scheme script 只能輸出一個數字, 無法輸出一個向量或其他更複雜的東西。 基於這些原因它並不適合用來寫太長, 太複雜的程式。

作業

常態分佈曲線

  1. 請自行從頭製作 常態分佈 曲線如圖。 可以移動的地方包含:
    • e1: x 軸上的單位點。 控制整個圖形的縮放。
    • mu: 常態分佈的平均值。 左右移動時應帶著整個圖形移動。
    • sigma: 常態分佈的一個標準差的位置。 移動時會改變曲線的高矮胖瘦, 但應永遠保持曲線底下面積為 1。
    • s: 水平軸上任一點, 用來查詢常態分佈在任意一點的函數值。
    注意移動 mu 與 sigma 的時候, s 的相對位置應該維持不變。 方程式請見上面連結的 Probability density function; 解答網址在本頁原始碼某處。