I want to make a function that takes a string "path" this is the path of a file that has only one line, I want to take this line and check it if it's a proper expression and if it is to build a tree out of this string, here is the code
`
loadExpression :: String -> Tree Char
loadExpression path = do
contents <- readFile path
if checkIfProper $ filter (/=' ') contents
then buildTreeFromString contents
else EmptyTree
`
But It gives me error "Couldn't match type IO' withTree' " . I know the IO string is different from the normal one but isn't <- suppost to do just that ? Converting IO string to a normal one. If I call buildTreeFromString with a string like "(1+2)*3" it works fine, same for the checkIfProper.
The whole error is :
Couldn't match type `IO' with `Tree'
Expected type: Tree String
Actual type: IO String
In the return type of a call of `readFile'
In a stmt of a 'do' block: contents <- readFile path
readFile has type FilePath -> IO String, so your do block is in the IO monad. Your entire function therefore returns an IO (Tree Char), not a Tree Char, so you need to change your type signature.
EDIT: You can separate the effectual and pure parts of your function, by creating a function to load the tree from an input string. You can then pass the string from readFile into this function:
readTree :: String -> Tree Char
readTree contents =
if checkIfProper $ filter (/=' ') contents
then buildTreeFromString contents
else EmptyTree
loadExpression then becomes:
loadExpression :: FilePath -> IO (Tree Char)
loadExpression path = do
contents <- readFile path
return (readTree contents)
or you can use fmap:
loadExpression = fmap readTree readFile
Related
This function takes an filepath and returns the content of the file.
this file includes a cuple of lines of the same length.
-- It's used to be an primitive picture.
parsePicture :: FilePath -> IO()
parsePicture fileName = do
content <- lines <$> readFile fileName
print content
Now I've tried to implement a function to flip the "picture" vertically:
type Picture = [[Char]]
flipVertical :: IO() -> Picture
flipVertical xs = map reverse xs
But I only get the following error code:
zuP12.hs:24:31: error:
• Couldn't match expected type ‘[[Char]]’ with actual type ‘IO ()’
• In the second argument of ‘map’, namely ‘xs’
In the expression: map reverse xs
In an equation for ‘flipVertical’: flipVertical xs = map reverse xs
|
24 | flipVertical xs = map reverse xs
| ^^
Failed, no modules loaded.
How can I use my function flipVertical on the result of parsePicture?
This function... returns the content of the file.
No it doesn't. It prints the content of the file, to STDOUT. For most purposes you should consider information you put to STDOUT to be gone – the information has left your program and is now on the terminal screen, or whereever else the user chooses to put it, but not accessible to the program anymore.
(Strictly speaking, it is possible to redirect STDOUT back into your own program, but it's a big hack, don't do this.)
Instead, you should change the function so it actually does return the content:
parsePicture :: FilePath -> IO Picture
parsePicture fileName = do
content <- lines <$> readFile fileName
return content
...or simply
parsePicture fileName = lines <$> readFile fileName
which behaves exactly the same (by the monad laws).
Also, I would rather call this loadPicture: parsing shouldn't involve file reading.
Of course, you can still print the contents later on, with something like
main = do
...
fooPicture <- parsePicture "foofilename"
print fooPicture
...
As for flipVertical, this shouldn't have anything to do with IO at all. It's simply a pure function
flipVertical :: Picture -> Picture
flipVertical xs = map reverse xs
which can be used like, for example
main = do
...
fooPicture <- parsePicture "foofilename"
print $ flipVertical fooPicture
...
or
main = do
...
fooVFPicture <- flipVertical <$> parsePicture "foofilename"
...
I have a type problem with this function
type Store = [(String, Float)]
evalParser :: String -> Store -> Float -- Boring function who returns a Float
programme :: Store -> IO()
programme store = do
putStr "#EvmInteractif:$> "
instruction <- getLine
putStrLn (show instruction)
if (estCommande (instruction) == True) then
do
res <- evalParser instruction store
putStrLn "TODO: execution de la commande"
programme store
And at the line of res's affectation I have this error :
Couldn't match expected type IO Float' with actual typeFloat'
In the return type of a call of `evalParser'
In a stmt of a 'do' block: v <- evalParser expr store
Can someone tell me the rigth syntax please ?
Thanks
evalParser is pure, you don't need to use do notation to call it. To shimmy fix it, you could just wrap it in a return to stick it in the IO Monad:
res <- return $ evalParser instruction store
To avoid the wrapping/unwrapping altogether though, just don't treat it as an impure value from the start:
let res = evalParser instruction store
I am having trouble reading in a level file in Haskell. The goal is to read in a simple txt file with two numbers seperated by a space and then commas. The problem I keep getting is this: Couldn't match type `IO' with `[]'
If I understand correctly the do statement is supposed to pull the String out of the Monad.
readLevelFile :: FilePath -> [FallingRegion]
readLevelFile f = do
fileContent <- readFile f
(map lineToFallingRegion (lines fileContent))
lineToFallingRegion :: String -> FallingRegion
lineToFallingRegion s = map textShapeToFallingShape (splitOn' (==',') s)
textShapeToFallingShape :: String -> FallingShape
textShapeToFallingShape s = FallingShape (read $ head numbers) (read $ head
$ tail numbers)
where numbers = splitOn' (==' ') s
You can't pull things out of IO. You can think of IO as a container (in fact, some interpretations of IO liken it to the box containing Schrödinger's cat). You can't see what's in the container, but if you step into the container, values become visible.
So this should work:
readLevelFile f = do
fileContent <- readFile f
return (map lineToFallingRegion (lines fileContent))
It does not, however, have the type given in the OP. Inside the do block, fileContent is a String value, but the entire block is still inside the IO container.
This means that the return type of the function isn't [FallingRegion], but IO [FallingRegion]. So if you change the type annotation for readLevelFile to
readLevelFile :: FilePath -> IO [FallingRegion]
you should be able to get past the first hurdle.
Let's look at your first function with explicit types:
readLevelFile f = do
(fileContent :: String) <-
(readFile :: String -> IO String) (f :: String) :: IO String
fileContent is indeed of type String but is only available within the execution of the IO Monad under which we are evaluating. Now what?
(map lineToFallingRegion (lines fileContent)) :: [String]
Now you are suddenly using an expression that is not an IO monad but instead is a list value - since lists are also a type of monad the type check tries to unify IO with []. What you actually wanted is to return this value:
return (map lineToFallingRegion (lines fileContent)) :: IO [String]
Now recalling that we can't ever "exit" the IO monad your readLevelFile type must be IO - an honest admission that it interacts with the outside world:
readLevelFile :: FilePath -> IO [FallingRegion]
I am writing package manager and I stuck at checking is file installed.
[1 of 1] Compiling Main ( ../src/beaver.hs, ../src/.o/Main.o)
../src/beaver.hs:57:37:
Couldn't match type `[Char]' with `Value'
Expected type: [Value]
Actual type: [[Char]]
In the second argument of `mapM', namely `(splitOn " " files)'
In a stmt of a 'do' block: mapM isFileInstalled (splitOn " " files)
Here is code of problematic function(s):
installpkg = do
args <- getArgs
pkgname <- readProcess "beaver-pkgname" [(args !! 1)] ""
extractpkg pkgname
files <- metaprop "files" pkgname
mapM isFileInstalled (splitOn " " files)
isFileInstalled f = do
dbcon <- openConnection "/var/lib/beaver/pkgs.db"
res <- execParamStatement dbcon "SELECT owner FROM files WHERE path = :path" [(":path", f)] :: IO (Either String [[Row Value]])
when (null res) (putStrLn "file exists")
closeConnection dbcon
I were searching for solution but I cannot find anything.
Also, is there a way to convert string or text to FilePath?
The type of execParamStatement in isFileInstalled is:
execParamStatement :: SQLiteResult a => SQLiteHandle -> String -> [(String, Value)] -> IO (Either String [[Row a]])
that means that [(":path", f)] is of type [(String, Value)] and f is dedecued to be of type Value.
This all means that isFileInstalled is deduced to take a Value as first argument.
Now in the other installpkg function you are calling:
mapM isFileInstalled (splitOn " " files)
and mapM is deduced to be from:
mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
to:
mapM :: (Value -> IO b) -> [Value] -> IO [b]
for whatever b is deduced there (it's hard to figure out because you don't put explicit type signatures for functions).
This all means that mapM is expected to get a list of [Value] from (splitOn " " files), which it's not. (splitOn " " files) is returning a [String] which is incompatible with [Value].
Since Value has a constructor that takes a String, you can use:
(map Text . splitOn " " $ files)
instead of:
(splitOn " " files)
and make it type check at least.
Also, is there a way to convert string or text to FilePath?
As far as FilePath is concerned, that's just an alias for String, so you don't need to convert to it to use it in the context where it's required a String.
Finally for the sake of those reading the code and you reasoning about it, write top level types signatures for functions, thanks.
I'm a beginner in Haskell and confused about this code I wrote
readRecords :: String -> [Either String Record]
readRecords path = do
f <- B.readFile path
map parseLogLine (C8.lines f)
But it gives me this error:
Main.hs:15:10:
Couldn't match type `IO' with `[]'
Expected type: [C8.ByteString]
Actual type: IO C8.ByteString
In the return type of a call of `B.readFile'
In a stmt of a 'do' block: f <- B.readFile path
In the expression:
do { f <- B.readFile path;
map parseLogLine (C8.lines f) }
parseLogLine's type signature is parseLogLine :: B8.ByteString -> Either String Record.
I'm completely surprised. B.readFile path should return IO ByteString and so f should be ByteString. C8.lines f should return [ByteString] and map should return [Either String Record].
Where am I wrong?
As a starting point, readRecords is defined with the wrong type. If the do block is to work in the IO monad, then it will produce an IO value, but you've defined it as returning [Either String Record] which is in the [] monad. That means that you can't call B.readFile which returns IO without triggering the type error you got.
Once you fix that, you'll find that the map expression on the last line of the do block has the wrong type because it produces [Either String Record] when it should produce IO [Either String Record]. Wrap the call in return to fix this.