Reputation: 1521
I have some troubles with Haskell's type system.
Situation:
readFile
inputParser
(from Parsec library)read_modules
do
expression are invalid in Haskell's type system[String]
vs IO String
vs [Char]
vs ...parse
should take a String
but when it gets it, it wants an IO String
suddenly (as the same argument), otherwise it wants a String
What do I want:
parse
function as third argumentHere 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:
What are the questions:
parse
- what readFile
gives me?Relevant weblinks:
Thank you all for your hints and comments.
Upvotes: 1
Views: 1823
Reputation: 77414
Here's what's causing the other error that you said was less important:
use :: [String] -> IO ()
use args =
do
init <- last args
The <-
operator is used within a do
block to extract something contained in a monad (in this case, IO
) so that you can work with the actual value trapped inside. But, args
here is of type [String]
, not IO [String]
, so you don't need to do that; you already pulled the argument list out of IO
with arg <- getArgs
in main.
If you want to assign a non-monadic value to a temporary variable inside a do
block, use let
instead, like this:
let x = last args
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, init
is the name of a function in the standard library, so you might want to use a different variable name.
Upvotes: 2
Reputation: 4049
First of all, since your function read_module
s performs I/O it must return something of type IO
. That means that you have to change a number of things in your function:
return
Right
branch in the case expression must use do-notationHere's a (hopefully) fixed version of your read_modules
function:
read_modules :: [String] -> IO [Module]
read_modules [] = return []
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 -> do
more <- read_modules rest
return (out ++ more)
return modules
I haven't tested it but I hope it will help you on the way.
Upvotes: 4
Reputation: 47062
This is wrong.
read_modules :: [String] -> [Module]
Should be
read_modules :: [String] -> IO [Module]
That is not all that you need to fix, but it will get you going.
Upvotes: 3