3 ms·
The difference at the high level is that assigning a variable creates a new scope. E.g. in C I would expect to be able to int i = 0; while (i < 5) {
by kqr 2y ago
The difference at the high level is that assigning a variable creates a new scope. E.g. in C I would expect to be able to
int i = 0;
while (i < 5) {
i = i+1;
printf("i: %d\n", i);
}
whereas in Haskell I could hypothetically something like
let i = 0 in
whileM (pure (i < 5)) $
let i = i + 1 in
printf "i: %d\n" i
but the inner assignment would not have any effect on the variable referenced by the condition in the while loop – it would only affect what's inside the block it opens.
(And as GP points out, i=i+1 is an infinite loop in Haskell. But even if it was used to build a lazy structure, it would just keep running the same iteration over and over because when the block is entered, i still has the value that was set outside.)
- eru 2y agoBtw, Haskell also supports mutable re-assignment of variables. But it's not something that's built into the language, you get mutable variables via a library. Just like you can get loops in Haskell via a library.
- kqr 2y agoOh, yeah, it's right there in the standard library. But one has to be a little more explicit about the fact that one is accessing truly mutable variables. For example, given the helper utilities checkIORef r p = fmap p (readIORef r) usingIORef r a = readIORef r >>= a the example can be written as main = do i <- newIORef (0 :: Int) whileM_ (checkIORef i (< 5)) $ do modifyIORef i (+1) usingIORef i (printf "i: %d\n") That said, even if one actually needs to mix mutable variables with I/O actions like printing, I'm not sure I would recommend using IORefs for it. But opening the can of MonadIO m => StateT Int m () is for another day.