Get value from IO String in Haskell [duplicate] - string

This question already has answers here:
A Haskell function of type: IO String-> String
(4 answers)
Closed 9 years ago.
I have a function with signature read_F95_src :: String -> IO [String]. This function is used elsewhere and cannot be changed.
I am reading in source lines and associated with a label as such src_lines = read_F95_src templ_src_name, which compiles and runs fine.
The problem is that I now have a function which takes in [String], and no matter how I try, I can't figure out a way to get the [String] value from src_lines.

You don't "extract" a value from IO. Instead you lift the rest of your computation into IO using fmap. So
read_F95_src :: String -> IO [String]
doSomethingWithStringList :: [String] -> Whatever
fmap doSomethingWithStringList :: IO [String] -> IO Whatever
fmap doSomethingWithStringList . read_F95_src :: String -> IO Whatever
You should get used to this pattern because it's going to happen to you a lot when you use Haskell. For example, if you want to do something with the IO Whatever you'll have to use the same trick again!

let src_lines = read_F95_src templ_src_name
(ss::[String]) <- src_lines
{- do whatever with ss -}

Extract the [String] like this inside a do block:
some_function :: IO [String]
some_function = do
dat <- read_F95_src "some data" -- Now the dat will contain the [String]
-- Now do all your stuffs on dat and return whatever you want to.
return dat
Once you have extracted the dat inside the function, you can apply other functions on it according to your logic and finally return whatever you need to.

Related

Haskell: read a text file of doubles and assign a list containing them to a list variable

Okay, I'm new to the Haskell community having come from Python and this is driving me crazy.
I have a text file looking something like:
"1.2
1.423
2.43".
I want to read this text file and store it as a list of doubles in list_var. So list_var = [1.2,1.423,2.43]. This list_var will be used further in the program.
I just don't seem to find an answer on how to do this, most answers can print out list_var, e.g. Haskell - Read a file containing numbers into a list but I need list_var further down the line!
I have tried:
get_coefficients :: String -> [Double]
get_coefficients file_1 = do
coefficients_fromfile <- readLines "test2.txt"
let coefficients = map readDouble coefficients_fromfile
return coefficients
which doesn't work, readLines is
readLines :: FilePath -> IO [String]
readLines = fmap lines . readFile
and readDouble is
readDouble :: String -> Double
readDouble = read
Thanks in advance!
Since you use return, your output is in a monad, in this case the IO monad. As the error message tells you, you should change this line:
get_coefficients :: String -> [Double]
To this:
get_coefficients :: String -> IO [Double]
This is because of a core principle of Haskell: referential transparency.
If you want to use the [Double] produced, you still have to keep it in an IO monad, like so:
main :: IO ()
main = do
-- This can be thought of as taking out values from the monad,
-- but requires the promise that it'll be put back into a monad later.
doubles <- get_coefficients "This argument does nothing, why?"
-- This prints the list of doubles. Note: it returns an IO (),
-- thus fufills the promise!
-- print :: Show a => a -> IO ()
print doubles

How to use readFile

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]

Couldn't match type `Char' with `[Char]' in Haskell? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Can I ask why I get this?
Couldn't match type Char' with[Char]'
Expected type: [String]
Actual type: [Char]
In the second argument of (:)', namelystart'
In the expression: (show gm : start)
main :: IO ()
main = do
c <- parseArguments <$> getArgs
input <- hGetContents stdin
either print (handleGM input) c
handleGM input Config{..} = do
handleGM <$> readFile tgrammer >>= either putStrLn (mapM_ putStrLn)
where
handleGM gm = do
gm' <- parseGM gm
case action of
Simulate -> printGrammer gm' input
printGrammer gm#TGrammer{..} input =
(show gm:start)
Data:
type TState = String
type TSymbol = Char
data TGrammer = TGrammer
{ neterminaly :: [TState]
, terminaly :: [TState]
, start :: [Char]
, rules :: [Rules]
}
deriving (Show)
data Rules = Rules
{ from :: TSymbol
, to :: String
}
deriving (Show)
There are quite a few things that are very weird about your code, so hopefully correcting them will help you solve your problem.
Type Signatures
You should always include type signatures on your top-level bindings, as well as any non-trivial where or let bindings. These are my best guesses as to what you intended the types to be:
handleGM :: String -> Config -> IO ()
printGrammer :: TGrammer -> String -> IO ()
Shadowed Binding
handleGM appears to be defined twice, once inside of itself in a where binding. This is really bad practice because it looks like you are trying to do a recursive call. You should consider renaming the internal function, or in this case, just writing it out in the do-notation, since its not recursive (and therefore doesn't need the where binding). In fact, you have misused <$>, which should only be used to map a pure function over an impure value. In this case, you are trying to use it to map an impure function of an impure value, which results in the confusing and not-what-you-want selection of Either String () as the type for the inside handleGM.
Operator overuse
It's best not to use <$> and >>= if your code isn't working, as it can hide what is actually happening, so write them out explicitly (do-notation) when you have problems like this.
Here is how I would revise handleGM so based on the above:
handleGM :: String -> Config -> IO ()
handleGM input Config{..} = do
a <- readFile tgrammer
b <- either putStrLn (mapM_ putStrLn) a
gm' <- parseGM b
case action of
Simulate -> printGrammer gm' input
[Char] doesn't match Char
This is because you used the cons operator (:) :: Char -> [Char] -> [Char], but the first argument you gave it was already a [Char] (namely, show gm). What you probably want is (++) :: [Char] -> [Char] -> [Char] which will put your two [Char] together into one longer [Char]. You probably also want to print to the terminal rather than just compute a [Char], which means you need to use a function like putStrLn :: String -> IO (). If these are accurate, here is what I would revise printGrammer to:
printGrammer :: TGrammer -> String -> IO ()
printGrammer gm#TGrammer{..} input = putStrLn (show gm ++ start)
Miscellaneous
You don't seem to actually do anything with input, so why bother passing it in at all?
You might benefit from turning on -Wall by passing it as an argument when you compile. It turns on all the compiler warning so it will tell you if you probably made a mistake.
You only have one case in your case. Why have the case there at all if it doesn't ever do anything different.
action seems to be pulled out of thin air; where does it come from?

Convert IO [String] to String [duplicate]

This question already has answers here:
A Haskell function of type: IO String-> String
(4 answers)
Closed 8 years ago.
I get through the contents of the page curl. Find the right data and formed on their basis the following query.
But the data are of type IO [String]. To request simply String.
How to convert IO [String] to String?
No way. What you can get there is IO String only.
Take a look at these related questions to understand why.
You can use unsafePerformIO (which has type IO a -> a and is thus impure), but this is almost certainly not what you are looking for. Instead, you can use fmap or >>= to perform operations on the string:
f :: String -> Int
f = read
io :: IO String
io = getLine
main :: IO ()
main = (f `fmap` io) >>= \x -> print x
The result of fmap and >>= is of course always IO a for some a, in order to maintain referential transparency.
This is evil (you didn't hear this from me!) but: unsafePerformIO.
I'm just talking about the type system though. Read the documentation carefully if you want to use it!
It's unsafe as the name suggests which means it is up to you to make extra-sure your usage makes sense.

Writing an IO String to stdout in Haskell

How do we print the output of a function that returns an IO String to the stdout? I am not able to use show or print.
If you want to print the result of the function foo :: Int -> IO String (for example), you can do
main = do
str <- foo 12
putStrLn str
or, without the do-notation,
main = foo 12 >>= putStrLn.
The do-notation is syntactic sugar for the second, which uses the fundamental (>>=) combinator, which has the type
(>>=) :: Monad m => m a -> (a -> m b) -> m b
IO is an instance of the Monad class, so you can use it here.
foo :: Int -> IO String
foo 12 :: IO String
putStrLn :: String -> IO ()
(foo 12) >>= putStrLn :: IO ()
How do we print the output of a function that returns an IO String to the stdout?
Well let's see. Here's a function that returns an IO String:
dumbFunction :: a -> IO String
dumbFunction x = getLine
dumbFunction is a dumb function (but a function nonetheless!). It ignores its input, and then returns getLine, which has the type IO String.
So you tell me, how do you print getLine :: IO String? The answer is, you don't! This is what we call an "IO action". Note that an IO action is not a function, because it does not take input. (However, IO actions might acquire input from, well, IO operations such as reading stdin, as getLine does. But it is not considered a "function" because it does not accept any traditional input)
So instead of printing out the action itself, you probably want to run the action, and then print the result. This can be done as Daniel Fischer described (with <-, which can be thought of as the "run" operator).

Resources