[Haskell-cafe] Network.CGI -- practical web programming example.

Luke Palmer lrpalmer at gmail.com
Sat Jun 27 20:26:47 EDT 2009

Your code examples are:

On Sat, Jun 27, 2009 at 6:07 PM, Edward Ing <edward.ing at gmail.com> wrote:

> saveFile n =
>    do          cont <- (liftM fromJust) $ getInputFPS "file"
>         let f = uploadDir ++ "/" ++ basename n
>         liftIO $ BS.writeFile f cont
>         return $ paragraph << ("Saved as " +++ anchor ! [href f] << f +++
> ".")


> saveFile n =
> do   cont <- getInputFPS "file"
>        let f = uploadDir ++ "/" ++ basename n
>       liftIO $ BS.writeFile f (fromJust cont)
>       return $ paragraph << ("Saved as " +++ anchor ! [href f] << f +++
> ".")

Consider the line x <- y in a do expression.  If y has type M a for some
monad M, then x has type a.

So, let's say you have a value f :: Maybe Int, and you want to return the
Int's stringification if it exists.  We can write this in these two ways:

do x <- f
   return (show x)

do x <- liftM show f
   return x

liftM :: (a -> b) -> (M a -> M b)   for any monad M.  That means if you want
to apply a function to a value which is currently wrapped in a monad
constructor, you need to "lift" it in.  liftM takes a function on ordinary
values to a function on wrapped values.  But *after* you bind, you don't
need to lift anymore.

Which of the two above styles to choose is a matter of style, and, in my
code at least, varies from situation to situation.

That said, you can write both of these snippets as "fmap show f" or "show
<$> f"  (where (<$>) is from Control.Applicative), which is how it would be
done in practice.

Does that make sense?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20090627/653a9667/attachment.html

More information about the Haskell-Cafe mailing list