更多 Abstraction 的例子。我想每個學過 Logo 的人都做過這個。
clearscreen
forward 40
right 90
forward 40
right 90
forward 40
right 90
forward 40
right 90
就是畫正方的方法。根據上次所講,要找出 Pattern ,上面程序的 forward 40 和 right 90 重覆了四次。我們可用 repeat 代替。
clearscreen
repeat 4 [forward 40
right 90
]
我們又可以定義一個 procedure 去劃方型,有長度 :length 為 argument 。
clearscreen
to square :length
repeat 4 [forward :length
right 90
]
endsquare 40
square 50
square 70
square 100
square 140
假設我想劃一個等邊三角形。
clearscreen
to triangle :length
repeat 3 [forward :length
right 120
]
triangle 60
end
正五邊型
clearscreen
to pentagon :length
repeat 5 [forward :length
right 72
]
end
pentagon 60
正八邊形
clearscreen
to octagon :length
repeat 8 [forward :length
right 45
]
endoctagon 60
又見到 pattern 出現。試分析 pattern 是甚麼。就是 repeat 次數等於多邊形的邊數,而右轉的角度每次不同。
若然你仍記得中一二的數學, n 邊形內角角度總和等於 (n-2) * 180 。如果 n 邊形是等邊,那麼每隻內角角度就是 ( ( n-2 ) * 180 ) / n ,以上面的八邊形為例,八邊形內角總和是 (8-2) * 180 = 1080 ,每隻內角就是 1080 / 8 = 135 度。
想想到底怎樣才可以叫龜劃出 135 度的內角?想當然的方法:
clearscreen
forward 50
right 135
forward 50
畫出來的內角並不是 135 度。正確的方法是要龜轉向 (180 - 135) = 45 度。
以上的算法可見,計算龜轉向角 theta 的數式是
theta = 180 - ( ( ( n - 2 ) *180 ) /n )
就此,可以定義一個多邊型 Procedure ,要輸入 :length, 邊數 :side 和轉向角 :theta 。
clearscreen
to polygon :length :side :theta
repeat :side [forward :length
right :theta
]
endpendown
polygon 60 3 120
penup forward 100
pendown
polygon 60 8 45
這樣並不好。原因每次想畫多邊形時,先要自行計算 theta 數值。每次我們想畫多邊形,我只想到想輸幾邊形以及大約劃幾大,很少會想 theta 的問題。以上的 polygon procedure 並不能完全的隱藏執行細節。
上面的 theta 算式可見, theta 是可以用幾多邊計算出來。若然我們可以指示電腦自行計算 theta 就好了。
Logo 實際上是可以作簡單的數學計算,例如以下的 procedure
to squaring :n
output :n * :n
end
再輸入
print squaring 4
會計出 16 。我們是可以將 procedure 回來的結果再變成同一個或另一個 procedure 的參數。例如
print squaring squaring squaring 4
結果會是 4 的八次方,即 65536 。這個要怎樣去理解呢?我們可以用 substitution model 思考。
思考電腦內有很多人在做不同的工作,當你輸入 print squaring squaring squaring 4 到電腦,這串指令可稱為 expression 。電腦要幹的工作是 evaluate 這個 expression 。電腦會先處理最後的 squaring 4 ,電腦把 4 這個數字交了給一個叫 Sally 的人做 squaring 工作, Sally 計算完得出結果 16 ,交給 Sharon ,指令可以想像變成
print squaring squaring 16
Sharon 計算 squaring 16 ,結果是 256 ,再交給 Sara ,指令變成
print squaring 256
Sara 計算 squaring 256 ,得出結果 65536 ,再交給 peter 。 Peter 把這個數字打出來。
根據同樣的理論,假設我們有一個叫根據多邊形邊數計算 theta 的 procedure ,名為 calculatetheta ,我們是可以修改以上的 polygon procedure 為:
to polygon :length :side
repeat :side [forward :length
right calculatetheta :side
]
end
假設輸入了 :side 為 3 ,用同樣的 substitution model 思考,電腦先找 Cathy 去計算 theta ,將結果 120 交給 Right 處理。那就可以畫出三角形。這種 blackbox abstraction 的方法,我們知道如此定義 polygon 是可行的,只不過我們沒有 calcultetheta 的 procedure 。
只要另外定義 calculatetheta ((注意,我只用 UCBlogo 測試以下 procedure ,在 papert 不 work ,但這個 online logo 是可以的。))
to calculatetheta :side
output 180 - ( ( ( :side-2 ) * 180 )/ :side )
end
現在的 polygon procedure 只需要輸入邊長和邊數就可以了。
polygon 20 3
polygon 20 4
polygon 20 9
polygon 20 21
很少見 21 邊形吧。但是你又見過 2 邊形未?
polygon 20 2
似乎是沒有 2 邊形的,當然也是沒有 1 邊形的。似乎 polygon 是需要控制邊數,必需要大於 2 。 Big idea #4 就是 boolean ,是 TRUE/FALSE。
在 Logo 輸入 print 3>2 ,結果是 1 。不過 print 2>3 ,結果是 0 。因為 3>2 是真, 2>3 是假。
我們想 polygon 能夠根據 :side 的大小做不同的事。
1. :side < 3 為真就[停止]
2. :side < 3 為假就[畫圖]
在 logo ,可用 ifelse 處理這個情況
to polygon :length :side
ifelse :side <3 [stop]
[repeat :side [forward :length
right calculatetheta :side
]]
end
這次 polygon 不再畫出兩邊形。
恭喜你!你已學識了能寫出所有程式的指令。 ((Logo 是 Turing complete 的,因為 Logo 有 +, if, 定義 procedure ,呼叫 procedure 和將數值記下來的能力。具有這些能力,已經可以寫出世上所有的程式,問題是要花幾多的時間。)) 從今以後,你所學的其他指令都並非必要,只是方便作業。 ((而事實上我也不想再教其他的指令,包括其他程式語言常用的 for loop, while loop 等等,定義 global variable 的 make 等等也並不需要。 Logo 是可以 purely functional 的。))