Haskell: 在 ST monad 中打印中间值
Haskell: printing intermediate values in ST monad
我正在尝试学习如何使用 ST Monad
。我想知道是否可以在采取行动时打印值。例如,在 ST Monad
:
中使用 Fibonacci
函数
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
TLDR: 不,您不能在 ST monad 中使用 print
或其他 IO-related 函数。在 IO monad 中使用 IORef
s 来实现可变性和打印值的能力。
完整答案:
在 Haskell 中,每个值都是不可变的。这有助于保持其纯度。 Purity 也不允许打印或用户输入等副作用。
然而,不能接受输入或打印输出的程序是无用的。因此,Haskell 在 IO
monad 中有 显式不纯函数 。通过 IORef
s,您还可以在 IO monad 中具有可变性。
但有时,您需要使用可变性来提高函数的效率,并且可以保证函数是纯粹的或引用透明(即相同的输入将始终给出相同的输出)。这就是 ST
monad 的目的。
ST
monad 不允许任意的副作用,例如打印,因为那会破坏它的纯度。它只允许在其中进行内部突变,并且一旦您使用 runST
转义了 monad,它就会对程序的其余部分显示为纯计算。
因此,如果您确实需要打印值并进行突变,请在 IO
monad 中使用 IORefs
。对于具有内部突变的纯函数,使用 ST
.
注意:可以使用 unsafePerformIO
, and to ST with unsafeIOToST
将 IO 添加到纯函数。顾名思义,它们是不安全的,除非绝对必要(通常不是),否则应避免使用。
我正在尝试学习如何使用 ST Monad
。我想知道是否可以在采取行动时打印值。例如,在 ST Monad
:
Fibonacci
函数
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
TLDR: 不,您不能在 ST monad 中使用 print
或其他 IO-related 函数。在 IO monad 中使用 IORef
s 来实现可变性和打印值的能力。
完整答案:
在 Haskell 中,每个值都是不可变的。这有助于保持其纯度。 Purity 也不允许打印或用户输入等副作用。
然而,不能接受输入或打印输出的程序是无用的。因此,Haskell 在 IO
monad 中有 显式不纯函数 。通过 IORef
s,您还可以在 IO monad 中具有可变性。
但有时,您需要使用可变性来提高函数的效率,并且可以保证函数是纯粹的或引用透明(即相同的输入将始终给出相同的输出)。这就是 ST
monad 的目的。
ST
monad 不允许任意的副作用,例如打印,因为那会破坏它的纯度。它只允许在其中进行内部突变,并且一旦您使用 runST
转义了 monad,它就会对程序的其余部分显示为纯计算。
因此,如果您确实需要打印值并进行突变,请在 IO
monad 中使用 IORefs
。对于具有内部突变的纯函数,使用 ST
.
注意:可以使用 unsafePerformIO
, and to ST with unsafeIOToST
将 IO 添加到纯函数。顾名思义,它们是不安全的,除非绝对必要(通常不是),否则应避免使用。