我正在嘗試學習如何使用ST Monad. 我想知道是否可以在采取行動時列印值。例如在以下Fibonacci函式中ST Monad:
fibST :: Integer -> Integer
fibST n
| n < 2 = n
| otherwise =
runST $ do
a <- newSTRef 0
b <- newSTRef 1
go n a b
where
go 0 a _ = readSTRef a
go n a b = do
a' <- readSTRef a
b' <- readSTRef b
writeSTRef a b'
writeSTRef b (a' b')
-- print "SOME INFORMATION HERE" <---
go (n - 1) a b
在這種情況下我該怎么辦?
@Vikstapolis 建議IORef改用
fibIO :: Integer -> IO Integer
fibIO n
| n < 2 = pure n
| otherwise =
do
a <- newIORef 0
b <- newIORef 1
go n a b
where
go 0 a _ = readIORef a
go n a b = do
a' <- readIORef a
b' <- readIORef b
writeIORef a b'
writeIORef b (a' b')
print a' -- intermediate values
go (n - 1) a b
uj5u.com熱心網友回復:
TLDR:不,您不能print在 ST monad 中使用或其他與 IO 相關的功能。在 IO monad 中使用IORefs 來實作可變性和列印值的能力。
完整答案:
在 Haskell 中,每個值都是不可變的。這有助于保持其純度。Purity 也不允許列印或用戶輸入等副作用。
然而,不能接受輸入或列印輸出的程式是沒有用的。因此,Haskell在monad 中有明確的不純函式。IO通過IORefs,您還可以在 IO monad 中具有可變性。
但有時,你需要使用可變性來提高函式的效率,并且可以保證函式是純的或參考透明的(即相同的輸入總是會給出相同的輸出)。這就是STmonad的目的。
STmonad 不允許像列印這樣的任意副作用,因為這會破壞它的純度。它只允許在其中進行內部突變,一旦你使用 逃逸 monad runST,它就會對程式的其余部分顯示為純計算。
因此,如果您確實需要列印值并進行突變,IORefs請在IOmonad 中使用。對于具有內部突變的純函式,請使用ST.
注意:可以使用 將 IO 添加到純函式,使用 可以將 IO 添加unsafePerformIO到 ST unsafeIOToST。顧名思義,它們是不安全的,除非絕對必要(通常??不是),否則應避免使用它們。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/427291.html
標籤:哈斯克尔
下一篇:按型別列印資料型別的結構
