5 ms·
Great description of IO, but I think it doesn't actually motivate monads. Your example of `getChar >> getChar` could be simply `[getChar, getChar]`. Why can't w
by ridiculous_fish 6y ago
Great description of IO, but I think it doesn't actually motivate monads. Your example of `getChar >> getChar` could be simply `[getChar, getChar]`. Why can't we just compose instructions into an ordinary list?
The answer is that we can, and Haskell used to work this way [1]! So as 'chowells' observed the monad-part of IO is almost incidental.
1: https://stackoverflow.com/questions/17002119/haskell-pre-monadic-i-o https://stackoverflow.com/questions/17002119/haskell-pre-mon...
- a1369209993 6y ago> Your example of `getChar >> getChar` could be simply `[getChar, getChar]`. Why can't we just compose instructions into an ordinary list? Because you can't pass results from a earlier list element into the computation of a later element. You'd need a list with existentially-quantified element types such as: {-# LANGUAGE ExistentialQuantification, GADTs #-} foreign import ccall "exit" exit :: Int -> IO () infixr 1 :> data IOList a = forall b. (:>) (a -> Act b) (IOList b) data Act b where Getchar :: Act Char Print :: String -> Act () Exit :: Int -> Act () main' :: IOList () main' = (\_->Getchar) :> (\c->Print ("Got '"++[c]++"'\n")) :> (\_ -> Exit 0) :> undefined runio :: a -> IOList a -> IO () runio a (f:>fs) = flip runio fs =<< case f a of Getchar -> getChar Print s -> putStr s Exit n -> exit n main = runio () main' where f :> g :> h :> ... is your list of instructions (rather than f : g : h : ..., which doesn't allow the response type of f to be related to the argument type of g).