--- tags: PLT --- # Cool Down 讀完 CanvasDesigner 了。還有不明白的地方,但學到很多。 CanvasDesigner 設計了一個小語言,該語言中的值(數字 num 和點 pt )都是隨時間變化的值,於是寫的人可以簡單地敘述複雜的關係。 在 Planets system 這個例子中: ``` _A = O + (cos(tha), sin(tha)) * ar _B = O + (cos(thb), sin(thb)) * br _C = B + (cos(thc), sin(thc)) * cr ``` `tha`, `thb`, `thc` 是隨時間改變的角度,它們決定了星球 A, B, C 所在的位置 `_A`, `_B`, `_C` 。 CanvasDesigner 執行時,所有的 expression 到 eval (也就是畫到畫面上)的時候才求值。 --- parsing 相關的 functions 有 `parseExpr`, `parseTuple`, `parseRange`, `parseTerm` 和 `parseOne` 。 ``` _A = O + (cos(tha), sin(tha)) * ar ``` `=` 左邊的是 symbol ,放在 symbol table `symTab` 中,不能重複定義。右邊的是 expression ,由 `parseExpr` 處理。 `parseExpr` 會從內而外找出所有 `()` 和 `[]` ,前者是 tuple ,交給 `parseTuple` ,後者是隨時間改變的 range ,交給 `parseRange` 處理。 這些 tuple 和 range 會被賦予新的名字,放在 symbol table 中待用。 然後 `parseExpr` 處理 `+` 和 `-` ,把 `*` 和 `/` 交給 `parseTerm` 處理。 num 和 pt 都可以任意 `*` 和 `/` ,但我還不明白 pt * pt 和 pt / pt 代表的意義。 `parseTerm` 再把 `*` 和 `/` 間的值交給 `parseOne` ,看看是不是在 symbol table 中,還是是個 JavaScript `Math` 函數,或者是內建的函數 `seg`, `bzr`, `qdr`, `arc`, `pi`, `dot` 。 結果都是 `function(timestamp){ return [...] }` 這樣的函數。 每次 `evalCanvas` 時,再賦予 `symTab` 中所有 symbol 當下的時間,求出值,並將沒有藏起來的 symbol 畫在畫面上。 --- 每次讀她的程式碼時,都讓我重新思考,如果我抱著 OOP 思維、從頭搭建 2D 繪圖架構,是不可能在 500 行內做出小而精巧的語言的。也很難想像沒有受到 FP 思維的影響(例如 state monad ),會想到可以將時間靠一個 lambda 藏起來。 ###### tags: note