2个使用do表示法的类似Haskell函数返回相同的结果,但一个被多次调用
nextState :: IO Int -> IO Int -- 0 1 0 2 0 1 0
nextState stateIO = do
value <- stateIO
putStrLn $ "Current state: " ++ show value
fmap (+1) stateIO
nextState' :: IO Int -> IO Int -- 0 1 2
nextState' stateIO = do
value <- stateIO
putStrLn $ "Current state: " ++ show value
return $ value + 1
main :: IO ()
main = do
let startStateIO = return 0 :: IO Int
let states = iterate nextState' startStateIO -- Use nextState or nextState'
stateInt <- states !! 3
print stateInt -- 3 in both cases
这个 Haskell 代码有 2 个函数,它们看起来都具有相同的行为。但是,打印调用显示它nextState被调用的次数比nextState'. 我有一个更大的项目,这是一个问题,我无法弄清楚如何转换该函数,以便它被调用的次数最少,因此我无法修复它。
为什么会发生这种情况以及如何在一个不太简单的示例中防止它发生?
请注意,fmap (+1)在我的实际项目中只是一个来自 的函数IO a -> IO a,而不是fmap (a -> a)- 整个事情都在 IO 方面工作,而不是修改内部使用的值(a->a)
回答
这个例子应该更容易理解,它是类似的:
twice :: IO () -> IO ()
twice act = do
() <- act
fmap id act -- like what you did in `nextState`
once :: IO () -> IO ()
once act = do
() <- act
return $ id () -- like what you did in `nextState'`
...或更短
twice :: IO () -> IO ()
twice act = act >> act
once :: IO () -> IO ()
once act = act
例如,
> twice (putStrLn "hello")
hello
hello
> once (putStrLn "hello")
hello
迭代once不做任何事情,因为它只是身份。
> iterate once (putStrLn "hello") !! 4
hello
迭代两次,但是...
Prelude> iterate twice (putStrLn "hello") !! 4
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
THE END
二维码