I have some troubles with Haskell’s type system.
Situation:
- Following program is taking list of filenames on the command-line
- For each filename its contents is read using the function
readFile - Contents of each file is passed to
inputParser(from Parsec library) - Rest is not so important
- Main problem is in function
read_modules - First two statements of the
doexpression are invalid in Haskell’s type system - Problem is conflict between
[String]vsIO Stringvs[Char]vs … - Function
parseshould take aStringbut when it gets it, it wants anIO Stringsuddenly (as the same argument), otherwise it wants aString
What do I want:
- Read each file’s content
- Pass that content to the
parsefunction as third argument
Here is the code:
module Main where
import System.IO
import System.Environment
import Text.ParserCombinators.Parsec
import InputParser
import Data
usage :: IO ()
usage = putStrLn "Usage: x file file file option"
parse_modules :: String -> [Char] -> Either ParseError [Module]
parse_modules filename input = parse inputParser filename input
read_modules :: [String] -> [Module]
read_modules [] = []::[Module]
read_modules (filename:rest) =
do
content <- readFile filename -- HERE is the problem
modules <- case parse_modules filename content of -- HERE is problem too
Left error -> do
putStr "parse error at "
print error
Right out -> out ++ (read_modules rest)
return modules
use :: [String] -> IO ()
use args =
do
init <- last args
filenames <- take (length args - 1) args
modules <- read_modules filenames
return ()
main :: IO ()
main = do args <- getArgs
if length args < 2
then usage
else use args
Here are the errors GHC outputs:
ghc --make -o x.hs input-parser.hs data.hs
[3 of 3] Compiling Main ( x.hs, x.o )
x.hs:19:4:
Couldn't match expected type `IO String'
against inferred type `[String]'
In a stmt of a 'do' expression: content <- readFile filename
In the expression:
do content <- readFile filename
modules <- case parse_modules filename content of {
Left error -> do ...
Right out -> out ++ (read_modules rest) }
return modules
In the definition of `read_modules':
read_modules (filename : rest)
= do content <- readFile filename
modules <- case parse_modules filename content of {
Left error -> ...
Right out -> out ++ (read_modules rest) }
return modules
-- THIS ERROR is somewhat not important
x.hs:30:4:
Couldn't match expected type `[Char]'
against inferred type `IO Char'
Expected type: String
Inferred type: IO Char
In a stmt of a 'do' expression: init <- last args
In the expression:
do init <- last args
filenames <- take (length args - 1) args
modules <- read_modules filenames
return ()
make: *** [x] Error 1
What is the problem:
- I cannot understand what I should pass where – I kind of know what I want, but I don’t get the syntax or the style.
- I am new to Haskell.
- Haskell’s types…
What are the questions:
- How do I fix the presented type issue?
- What should I put into
parse– whatreadFilegives me? - Are the types compatible?
- Isn’t there need for some type of conversion?
Relevant weblinks:
- http://book.realworldhaskell.org/read/using-parsec.html
- http://www.zvon.org/other/haskell/Outputprelude/readFile_f.html
- http://www.haskell.org/pipermail/haskell/2002-November/010748.html
Thank you all for your hints and comments.
Here’s what’s causing the other error that you said was less important:
The
<-operator is used within adoblock to extract something contained in a monad (in this case,IO) so that you can work with the actual value trapped inside. But,argshere is of type[String], notIO [String], so you don’t need to do that; you already pulled the argument list out ofIOwitharg <- getArgsin main.If you want to assign a non-monadic value to a temporary variable inside a
doblock, useletinstead, like this:It looks like you’re making the same mistake in several other places as well, not just that line. Having to treat monadic vs. non-monadic values differently like that, when you just want to make a temporary variable inside your function, is an easy thing to get confused about for someone new to the language.
By the way,
initis the name of a function in the standard library, so you might want to use a different variable name.