3

I'm trying to write a simple Fibonacci web server using WAI but I just can't figure out the types. This code is the essence of what I want to do, but it's broken. The getQueryArg function returns a Maybe ByteString and I want to use that in my fibHandler function.

  1. How do I correctly handle the Maybe in my fibHandler?
  2. How do I call putStrLn on a Maybe? I'm trying fmap but I can't seem to get it right.

 

{-# LANGUAGE OverloadedStrings #-}
import Network.Wai
import Network.HTTP.Types
import Network.Wai.Handler.Warp (run)
import Data.ByteString.Lazy.Char8 ()  -- Just for an orphan instance
import Control.Monad.IO.Class (liftIO)
import Data.Conduit
import Data.String.Utils
import Data.ByteString as BS (ByteString, putStrLn)
import Data.ByteString.Char8 as B (unpack)
import Data.Text as T (intercalate, pack, unpack)

app :: Application
app req
    | rawPathInfo req == "/fib" = fibHandler req
    | otherwise = notFoundHandler

fibHandler :: Request -> ResourceT IO Response
fibHandler req = do
    let nStr = getQueryArg (queryString req) "n"
    fmap (liftIO . BS.putStrLn) n
    let n = read nStr
    return $ responseLBS
        status200
        [("Content-Type", "text/plain")]
        (show $ fib n)

fib :: Int -> Int
fib n = foldl (*) 1 [1..n]

getQueryArg :: Query -> BS.ByteString -> Maybe BS.ByteString
getQueryArg [] key = Nothing
getQueryArg ((k,v):qs) key
    | k == key = Just v
    | otherwise = getQueryArg qs key

notFoundHandler :: ResourceT IO Response
notFoundHandler = return $ responseLBS
    status404
    [("Content-Type", "text/plain")]
    "Not found"

main :: IO ()
main = do
    BS.putStrLn $ "http://localhost:8080/"
    run 8080 $ app

[Update: a working copy of this code is here: https://gist.github.com/3145317]

unor
  • 92,415
  • 26
  • 211
  • 360
Sam
  • 2,620
  • 2
  • 26
  • 28
  • In what way is this broken? You've mentioned how you'd like it improved (handle `Maybe`..) but not what's broken with the current code... – sarnold Jul 18 '12 at 23:42
  • Just a note: `fib n = foldl (*) 1 [1..n]` is the factorial, not the Fibonacci number. – Daniel Fischer Jul 19 '12 at 12:04
  • 1
    @sarnold it is broken because it doesn't handle Maybe from `getQueryArg`. @DanielFischer yup you are totally right, thanks! – Sam Jul 19 '12 at 16:19

1 Answers1

6

The simplest thing to do with Maybe values is to use case.

case getQueryArg foo bar of
    Nothing -> {- something went wrong, write some code to report an error -}
    Just x  -> {- everything went okay, and x is the result of the successful computation -}

Once you've done this a couple dozen times, you can graduate to the shorthand versions:

maybe ({- went wrong -}) (\x -> {- successful x -}) (getQueryArg foo bar)
fromMaybe {- default value -} (getQueryArg foo bar)
traverse_ B.putStrLn (getQueryArg foo bar) -- this trick is a personal favorite
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380