歡迎來到 Factor!Factor 是一門串接式語言:不是像square(add(2, 3))那樣呼叫函式,而是把一排詞由左至右寫出來,也就是2 3 + square,讓它們透過共用的資料堆疊把值傳給彼此。想像碼頭上堆著一疊貨箱,最新的放在最上面。
!會開始一行註解,Factor 會忽略從!到行尾的所有內容。下面的範例用!來說明程式碼在做什麼。
寫下一個字面值會把它推入堆疊頂端。程式碼由左至右讀取。
1 2 3 ! stack (bottom → top): 1 2 3
每個詞都會從堆疊頂端讀取輸入,並把輸出寫回頂端。.會彈出最上面的值並印出它,.s則會印出整個堆疊而不消耗任何東西,這在查看某段程式碼留下什麼時很方便。
每個詞都會用( inputs -- outputs )這種形式的堆疊效應來記錄。這是該詞的契約:詞會從堆疊頂端彈出輸入,並把輸出留在原本的位置。裡面的名稱是給人看的說明,堆疊本身是按位置決定的,不是按名稱。堆疊頂端對應的是最右邊的名稱。
:開始一個詞的定義,接著是堆疊效應,然後是主體,最後用;結束。Factor 的編譯器會檢查主體是否真的留下堆疊效應所宣告的內容。
: restow ( a b -- b a ) swap ;
這些kernel詞會重新排列堆疊頂端,而不做任何算術運算,它們只是把貨箱搬來搬去:
dup ( x -- x x ) ! copy the top crate
drop ( x -- ) ! remove the top crate
swap ( x y -- y x ) ! flip the top two
over ( x y -- x y x ) ! copy the second crate onto the top
nip ( x y -- y ) ! remove the second crate
rot ( x y z -- y z x ) ! roll the third crate up to the top
當一個貨箱必須同時供兩個詞使用時,就用dup;要丟掉一個貨箱時用drop;最上面兩個的順序不對時用swap;要處理下面那個貨箱時用over或nip;要把埋在下層的貨箱搬到最上面時用rot。
更廣泛的家族(-rot、dupd、swapd、2dup……)也遵循同樣的概念,這些詞之後你就會遇到。
排成一列的詞會由左至右執行:每個詞都會作用於前一個詞所留下來的堆疊。以下是swap nip對堆疊1 2(底部 → 頂端)的影響,一次一個詞:
1 2 ! 1 2 the starting crates
swap ! 2 1 swap flipped the top two
nip ! 1 nip dropped the 2nd-from-top crate (the 2)
還有dup rot作用在同樣的起始貨箱上,同樣是一次一個詞:
1 2 ! 1 2 the starting crates
dup ! 1 2 2 dup copied the top crate
rot ! 2 2 1 rot rolled the 3rd-from-top crate up to the top
詞使用lowercase-kebab-case:小寫字母以連字號連接。
你是一名碼頭裝卸工,正在碼頭上重新堆放貨箱。每一項任務都只要定義一個詞,而且詞的內容只會用到搬移堆疊的詞,不會用到算術。
定義swap-crates這個詞。它會從堆疊取下兩個貨箱,然後以相反的順序把它們放回去。
1 2 swap-crates .s
! 2
! 1
定義clear-spill這個詞。它會從堆疊取下三個貨箱,留下底下兩個,丟掉最上面那個。
1 2 3 clear-spill .s
! 1
! 2
定義peek-under這個詞。它會從堆疊取下兩個貨箱,把它們放回去,並在最上面放一份下面那個貨箱的副本。
1 2 peek-under .s
! 1
! 2
! 1
定義tidy-deck這個詞。它會從堆疊取下三個貨箱(順序為x y z),然後留下z z y:丟掉最底下的貨箱,接著把最上面那個貨箱的兩份留在中間那個貨箱上方。
1 2 3 tidy-deck .s
! 3
! 3
! 2