
Hello! I am trying and failing to use one monad in another. A tiny example is enclosed, where I try to use IO to help along a State-ful computation. Is the real mistake in do_next? Is there a minimal rewrite that will get this working that I can use as a template for other things? Or, is there a good tutorial somewhere on this type of thing? Any pointers are much appreciated! -- Mark

On Sat, 12 Apr 2003, Scott Turner wrote:
On Saturday 12 April 2003 09:52, Mark T.B. Carroll wrote:
Hello! I am trying and failing to use one monad in another. Is there a minimal rewrite that will get this working ... ? Yes. Just add lift. do count <- lift $ get_length name
Wow. Thanks. That's wonderful! Much food for thought there. -- Mark

Mark T.B. Carroll wrote:
Hello! I am trying and failing to use one monad in another. A tiny example is enclosed, where I try to use IO to help along a State-ful computation. Is the real mistake in do_next? Is there a minimal rewrite that will get this working that I can use as a template for other things? Or, is there a good tutorial somewhere on this type of thing? Any pointers are much appreciated!
Combining monads isn't straightforward. There is a paper on the topic, at: http://cm.bell-labs.com/cm/cs/who/wadler/topics/monads.html#combining-monads However, you can't really combine the IO monad in the way that the above paper describes. The most direct way to fix your program is to use an IORef instead of a state monad, e.g.
import IORef
update_best_with :: IORef (String, Int) -> (String, Int) -> IO () update_best_with ref (current_name, current_count) = do (best_name, best_count) <- readIORef ref when (current_count > best_count) $ do writeIORef ref (current_name, current_count)
do_next :: IORef (String, Int) -> String -> IO () do_next ref name = do count <- get_length name update_best_with ref (name, count)
longest_file :: [String] -> IO (String, Int) longest_file names = do ref <- newIORef ("none", 0) mapM_ (do_next ref) names readIORef ref
A more elegant solution would be to generate a list of filename/length pairs (e.g. using mapM), then just use maximumBy to select the longest, e.g.
get_length' :: String -> IO (String, Int) get_length' name = do length <- get_length name return (name, length)
longest_file :: [String] -> IO (String, Int) longest_file names = do pairs <- mapM get_length' names return $ maximumBy cmp pairs where cmp (_, l1) (_, l2) = compare l1 l2
--
Glynn Clements
participants (4)
-
Glynn Clements
-
Mark Carroll
-
Mark T.B. Carroll
-
Scott Turner