[Haskell-beginners] Either Monadic Trouble

iæfai iaefai at me.com
Mon Nov 9 04:01:43 EST 2009


With the below code, I am getting an error that I cannot resolve…


Chess.hs:52:82:
     Couldn't match expected type `Map [Char] [Char]'
            against inferred type `Either ParseError ConfigMap'
     In the third argument of `findWithDefault', namely `c'
     In the `documentRoot' field of a record
     In the first argument of `return', namely
         `Config {documentRoot = (findWithDefault "web" "Document- 
Root" c)}'


The specific code is:

getConf :: FilePath -> IO (Either ParseError Config)
getConf filePath
     = return $ do
         c <- readConfig filePath  -- (Either ParseError ConfigMap)
         return Config { documentRoot = Map.findWithDefault "web"  
"Document-Root" c }


The type of c should be Either ParseError ConfigMap, which by my  
understanding of the Either monad would cause the c to be the Right  
side stripped, or skipped if Left.

Full source for the module is below, and full project is hosted at http://patch-tag.com/r/iaefai/chess

For some general information, I am replacing ConfigFile dependancy  
with a Parsec based config parser (I call it SimpleConfig) that suits  
my needs - it came from

http://www.serpentine.com/blog/2007/01/31/parsing-a-simple-config-file-in-haskell/ 
  originally and I modified it. On windows ConfigFile's dependancy on  
a posix regex library was causing trouble, so this is the effort to  
get rid of that dependancy.

Any thoughts would be useful.

There is one associated thought…

The original function used to get configuration back to the program is
-- Mostly from Chris Done's Blog  
getConf :: FilePath -> IO (Either (C.CPErrorData, String) Config)
getConf filePath = runErrorT $ do
     let cp = C.emptyCP { optionxform = id }
     contents <- liftIO $ readFile filePath
     config <- C.readstring cp contents
     let get = C.get config "DEFAULT"
     Config <$> get "Document-Root"

I noted it used <$> and in the code that I retrieved originally from  
Chris Done's blog (no longer able to find it) used <*> for additional  
items. I would like some easy method of constructing the new Config  
structure in my new code, especially if it can be done without the  
record syntax like this thing gets away with. I am not sure how this  
thing associated "Document-Root" with documentRoot mind you.

Thank you again.
iæfai.


-- 
import Network.Shed.Httpd
import Network.URI

import Data.List.Split

import Data.Either
import Data.Map as Map

import Text.ParserCombinators.Parsec

import Control.Monad.Error
import Control.Applicative

import System.Directory

import ChessBoard
import SimpleConfig

data Config = Config { documentRoot :: String } deriving (Read, Show)



main :: IO ()
main
     = do
         let docPath = ""
         let config = Config { documentRoot = "" }
         putStrLn $ "Using document root: " ++ docPath
         putStrLn "Starting up httpd on port 6666"
         server <- initServer 6666 (request config)
         return ()

request :: Config -> Request -> IO Response
request config req
     = do
         putStrLn $ "Recieved " ++ (show $ uriPath $ reqURI req)
         case url of
             "ajax" : _ -> return $ Response 404 [] "Not found."
             _   -> do str <- readFile ((documentRoot config) ++ uri)
                       return $ Response 200 [] str
         where url = drop 1 $ splitOn "/" uri
               uri = uriPath $ reqURI req



getConf :: FilePath -> IO (Either ParseError Config)
getConf filePath
     = return $ do
         c <- readConfig filePath  -- (Either ParseError ConfigMap)
         return Config { documentRoot = Map.findWithDefault "web"  
"Document-Root" c }  -- **** ERROR


More information about the Beginners mailing list