這是彈跳球代碼。我試圖讓'appendFile'在更新功能上運行,所以當球從墻上反彈時,'appendFile'會將px和px值寫入檔案“log.txt”
import Graphics.Gloss
import Graphics.Gloss.Data.ViewPort (ViewPort)
main :: IO ()
main =
simulate
(InWindow "Bouncing ball" (width, height) (50, 50))
white
30
initial
view
update
但我遇到了麻煩,因為“appendFile”只在簽名 IO 上運行。而且我不知道如何在這種情況下應用它
update :: ViewPort -> Float -> World -> World
update _ _ World {position = (px, py), velocity = (vx, vy)} =
let
appendFile "Log.txt" ("" show px " " show py "")
newPx = px vx
newPy = py vy
newVx = if newPx >= fromIntegral width || newPx <= 0 then - vx else vx
newVy = if newPy >= fromIntegral height || newPy <= 0 then - vy else vy
in World {position = (newPx, newPy), velocity = (newVx, newVy)}
uj5u.com熱心網友回復:
Haskell 對副作用非常嚴格。寫入檔案是一種副作用,純函式(如您的update)不允許有副作用。
如果您只想記錄資料以進行除錯,那么您可以使用臭名昭著的 accursed unsafePerformIO,它為純計算提供了進入 IO monad 的后門。名稱中“不安全”位的原因是,它沒有承諾 IO 操作的運行頻率,或者即使它完全運行。
但是您上面的代碼實際上不會呼叫appendFile. 事實上這是一個語法錯誤;alet引入了可能在代碼中使用的值,但您沒有為appendFile.
你需要更多類似的東西:
let
... omitted
in seq
(unsafePerformIO $ appendFile "Log.txt" (show px " " show py "\n")
World {position = (newPx, newPy), velocity = (newVx, newVy)}
seq是一個魔術函式,它的第一個引數是“嚴格的”,因此在unsafePerformIOnew 之前被評估World,即使沒有使用第一個引數的結果。
然而,這是一個 kluge。您不應該unsafePerformIO用于生產代碼。這是對編譯器的謊言。如果你養成了它的習慣,那么編譯器就會報仇雪恨,而且它不會很漂亮。
如果這是用于生產代碼,那么您應該改用simulateIO. 這需要一個回傳IO值的更新函式,因此您可以撰寫update回傳一個IO World,每個人都會很高興。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/427246.html
