Haskell Design: Fighting IO

I am a beginner haskell programmer, and I am trying to write a Haskell cgi that will read from a MySQL database and output JSON. I can generate the correct JSON, but I cannot get the data types correctly in order to correctly output JSON. I also think that I primarily think that is still necessary. Here is my code. Note that getTopBrands provides json output.

My problem is that I cannot figure out how to return "[Char]" from getTopBrands, and not "IO [Char]". I think I still think it is necessary. Any pointers, suggestions for fixing this would be greatly appreciated. Please let me know if I need to provide the rest of the code.

RODB.hs:

{-# LANGUAGE RecordWildCards, OverloadedStrings, PackageImports #-} module Main where import RODB import ROOutput import System.Environment import Database.HDBC import Network.Socket(withSocketsDo) import Network.CGI import Text.XHtml import qualified "bytestring" Data.ByteString.Lazy.Char8 as LBS import Data.Aeson page :: Html page = body << h1 << str main = runCGI $ handleErrors cgiMain cgiMain :: CGI CGIResult cgiMain = do out <- getTopBrands 10 1 setHeader "Content-type" "application/json" output $ renderHtml page out getTopBrands :: Integer -> Integer -> IO [Char] getTopBrands limit sorted = do let temp = 0 dbh <- connect "127.0.0.1" "ReachOutPublicData" "root" "admin" "/tmp/mysql.sock" if sorted == 1 then do brandlist <- getBrands dbh limit True json <- convPublicBrandEntrytoJSON brandlist return $ LBS.unpack json else do brandlist <- getBrands dbh limit False json <- convPublicBrandEntrytoJSON brandlist return $ LBS.unpack json 
+4
source share
1 answer

As Niklas B said , getTopBrands is in IO correctly, as it depends on I / O. I think your problem is that you get a type error when you try to use it directly,

 cgiMain :: CGI CGIResult cgiMain = do out <- getTopBrands 10 1 setHeader "Content-type" "application/json" output $ renderHtml page out 

since all instructions in the do block must belong to the same monad, and the rest of the block is in CGI . But CGI is MonadIO , so you can just liftIO insert it into CGI ,

 cgiMain :: CGI CGIResult cgiMain = do out <- liftIO $ getTopBrands 10 1 setHeader "Content-type" "application/json" output $ renderHtml page out 

The next point that Niklas raised is also right, the second argument of Integer getTopBrands should really be Bool . However, even with its current type, code duplication is completely unnecessary, the difference between the two branches is just a Bool argument for getBrands , therefore

 getTopBrands :: Integer -> Integer -> IO [Char] getTopBrands limit sorted = do let temp = 0 dbh <- connect "127.0.0.1" "ReachOutPublicData" "root" "admin" "/tmp/mysql.sock" brandlist <- getBrands dbh limit (sorted == 1) json <- convPublicBrandEntrytoJSON brandlist return $ LBS.unpack json 

just pass it the condition in which you are branched.

Third point of Niklas

I also do not understand why convPublicBrandEntrytoJSON will need to live in IO , but since you did not specify its definition, I cannot offer an improvement here.

also looks very correct, conversion is usually a pure function. If the only reason she is in IO is the ability to write

 json <- convPublicBrandEntrytoJSON brandlist 

you should know that you can bind the results of pure functions in a do-block

 let json = convPublicBrandEntrytoJSON brandlist 

using let .

+8
source

All Articles