我想了解Haskell中的monad系統。我以前編程實驗的大約80%是用C語言編寫的,但具有諷刺意味的是,Haskell的必要部分是最難理解的。列表操作和懶惰評估更清晰。無論如何,我想讓ghc接受這段代碼。我知道代碼根本沒有意義。最明顯的是,我通過了Bool
,其中IO Bool
預計。但這不是唯一的問題。我知道這是一個愚蠢的問題,但請幫助我進一步理解Haskell語言。Haskell命令循環
import Control.Monad
while :: Monad m => m Bool -> m() -> m()
while cond action = do
c <- cond
when c $ do
action
while cond action
main :: IO()
main = do
i <- 0
while (i < 10) $ do
i <- i + 1
print i
下面是我終於做到了。我知道allocaArray
沒有必要,但使用起來非常有趣。 Haskell真的沒有限制,非常強大。
import Control.Monad
import Data.IORef
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Array
while :: Monad m => m Bool -> m() -> m()
while cond action = do
c <- cond
if c then do
action
while cond action
else return()
main :: IO()
main = do
let n = 10
allocaArray n $ \p -> do
i <- newIORef 0
while (liftM (< n) (readIORef i)) $ do
i2 <- readIORef i
poke (advancePtr p i2) i2
modifyIORef i (+ 1)
writeIORef i 0
while (liftM (< n) (readIORef i)) $ do
i2 <- readIORef i
(peek $ advancePtr p i2) >>= print
modifyIORef i (+ 1)
讓我們從明顯的開始。 '我'不是一個可變的變量,並不僅僅因爲你有一個單子。 'i < - i + 1'是指兩個不同的'i's。 –
Haskell中'while'構造很少使用,我想這正是因爲在Haskell中它實際上並不允許您以習慣於使用命令式語言的人的自然方式使用「變量」。你*可以*更笨拙地做同樣的事情,但是你必須使用可變引用,如'Data.IORef'或'Control.Concurrent.MVar'中的可變引用。除非你真的需要可變的更新,否則通常更好地表達它的功能。 –
請注意,以這種方式使用'IORef'會導致循環計數器被「裝盒」,因此每次迭代都會分配一個新的'Int'盒,並且訪問計數器涉及指針間接。當你處理更加功能強大的計數器時,GHC通常可以將它解開,從而加快編碼速度。 – dfeuer