I'm trying to understand the monad system in Haskell. About 80% of my previous programming experiance is in C, but ironically the imperative part of Haskell is the hardest to understand. List manipulation and lazy evaluation was much more clear. Anyway I want to make ghc accept this code. I know the code doesn't make sense at all. Most obviously, I'm passing a Bool where IO Bool is expected. But that's not the only problem. I know this is a stupid question, but please help me to further my understanding of the Haskell language.
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
Here's how I finally did it. I know allocaArray isn't necessary, but it was very fun to use. Haskell really has no limits, very powerful.
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)
iis not a mutable variable, and doesn't become one simply because you have a monad around.i <- i + 1refers to two differentis.whileconstruction is rather rarely used in Haskell, I think precisely because in Haskell it doesn't actually allow you to use "variables" in a natural way for people used to imperative languages. You can do the same thing more awkwardly, but you have to use mutable references such as those inData.IOReforControl.Concurrent.MVar. Unless you really need mutable update, it's generally better to express it functionally.IORefin this manner leads to the loop counter being "boxed", so a newIntbox will be allocated on each iteration and accessing the counter involves pointer indirection. When you deal with a more functional-style counter, GHC can usually unbox it, leading to faster code.Foreignstuff? Do you actually need to deal with foreign code? Do you have a reason to make the garbage collector treat the array as foreign? If not, you should consider using unboxed mutable vectors (from thevectorpackage) instead.