patternModerate
Simple xkcd comic downloader
Viewed 0 times
xkcddownloadercomicsimple
Problem
I'd really appreciate some harsh/constructive criticism of what I would consider as my first program in Haskell. The program should download all of the xkcd comics into a folder in the current directory.
I basically just threw the kitchen sink at it, using anything I found remotely interesting in RWH and on the Haskell wiki, so I'm 99% sure most of it is unnecessary or overkill. I tried using most popular libraries I could find.
I wasn't clear on how to handle errors, how to deal with the filesystem efficiently, and how to use Text.JSON correctly.
hpaste link
```
{-# Language PackageImports #-}
module Main where
import System.FilePath (takeFileName, ())
import System.IO
import System.Environment
import System.Posix.User
import System.Directory
import Control.Monad (liftM, forM_, replicateM_)
import Control.Concurrent (forkIO)
import Control.Concurrent.STM
import Data.List (delete)
import Network.HTTP
import qualified Data.ByteString.Lazy.Char8 as L
import "mtl" Control.Monad.Error
import Network.URI (parseURI)
import Control.Applicative
import Control.Exception
import qualified Network.Stream as Stream (Result)
import Control.Arrow
import Text.JSON
----------------------------------------------------------------------
main = do
dir comics) $ writeTChan comicQueue
workers IO (Either IOException (Stream.Result (Response String)))
tryRequest = try . simpleHTTP
simpleHttpE request = do
response throwError $ show err
Right rsp -> return rsp
getResponseBodyE = either (throwError.show) (return.rspBody)
fetchHtmlA = Kleisli getRequestE >>>
Kleisli simpleHttpE >>>
Kleisli getResponseBodyE
fetchHTMLBody url = runErrorT $ runKleisli fetchHtmlA url
----------------------------------------------------------------------
xkcd = "http://xkcd.com/"
xkcdJSONUrl Current = xkcd ++ "info.0.json"
xkcdJSONUrl (ComicNumber n) = xkcd ++ show n ++ "/info.0.json"
xkcdFetchJSON :: ComicNumber -> IO (Either String String)
xkcdFet
I basically just threw the kitchen sink at it, using anything I found remotely interesting in RWH and on the Haskell wiki, so I'm 99% sure most of it is unnecessary or overkill. I tried using most popular libraries I could find.
I wasn't clear on how to handle errors, how to deal with the filesystem efficiently, and how to use Text.JSON correctly.
hpaste link
```
{-# Language PackageImports #-}
module Main where
import System.FilePath (takeFileName, ())
import System.IO
import System.Environment
import System.Posix.User
import System.Directory
import Control.Monad (liftM, forM_, replicateM_)
import Control.Concurrent (forkIO)
import Control.Concurrent.STM
import Data.List (delete)
import Network.HTTP
import qualified Data.ByteString.Lazy.Char8 as L
import "mtl" Control.Monad.Error
import Network.URI (parseURI)
import Control.Applicative
import Control.Exception
import qualified Network.Stream as Stream (Result)
import Control.Arrow
import Text.JSON
----------------------------------------------------------------------
main = do
dir comics) $ writeTChan comicQueue
workers IO (Either IOException (Stream.Result (Response String)))
tryRequest = try . simpleHTTP
simpleHttpE request = do
response throwError $ show err
Right rsp -> return rsp
getResponseBodyE = either (throwError.show) (return.rspBody)
fetchHtmlA = Kleisli getRequestE >>>
Kleisli simpleHttpE >>>
Kleisli getResponseBodyE
fetchHTMLBody url = runErrorT $ runKleisli fetchHtmlA url
----------------------------------------------------------------------
xkcd = "http://xkcd.com/"
xkcdJSONUrl Current = xkcd ++ "info.0.json"
xkcdJSONUrl (ComicNumber n) = xkcd ++ show n ++ "/info.0.json"
xkcdFetchJSON :: ComicNumber -> IO (Either String String)
xkcdFet
Solution
Looks pretty good. You're getting on top of stuff nicely. Some criticism:
- don't use package imports
- write type signatures for top level functions
- write comments!
- thread design looks good.
- don't use
if'. Haskell hasifalready.
- Kleisli needs documentation. Starting to go overboard at this point.
- don't mix too many concepts in one program: the code won't be maintainable.
Context
StackExchange Code Review Q#2574, answer score: 11
Revisions (0)
No revisions yet.