Reading file into string haskell [duplicate] - ios

This question already has answers here:
A Haskell function of type: IO String-> String
(4 answers)
Closed 7 years ago.
Rather simple problem, but one that I am having trouble to overcome. None of the examples I find online works, not sure if its because they are outdated and something in IO were changed in last 2-3 years, or I a missing something obvious.
I know that reading file with readFile returns IO String and there is no easy way to get rid of it, but supposedly easy way to read file into normal String is s<- readFile "filename" which works in command line, but I just cant make it work in a function.
getString ::IO String
getString = readFile "Input.txt"
Is rather simple, but returns IO String instead of String, and I am having trouble making s<- readFile "filename" work.
All I really want is simple function that returns file in a String and then I can deal with data in that string.
Ps I would love to see simple way to read file line by line function as well, as all examples seems to be incredibly complicated for what they are supposed to do and how easy is to perform those actions in any imperative programming language.

There isn't a function that turns an IO String into a String. You can use do notation like so*:
main = do
s <- readFile "somefile.txt"
doSomethingWith s
doSomethingWith :: String -> IO ()
doSomethingWith str = putStrLn str
but you will only have access to s as a String inside the do block, or in functions that are applied to s, like doSomethingWith.
* You can also use the equivalent desugared version, main = readFile "someFile.txt" >>= \s -> doSomethingWith s.

Related

How can two Haskell programs exchange an integer value via stdin and stdout without treating the data as text?

I am interested in learning how to send data efficiently between Haskell programs using standard input and output. Suppose I want to pipe two programs together: "P1" outputs the number 5 to stdout, and "P2" takes an integer from stdin, adds 1, and outputs it to stdout again. Right now, the best way I know to do this involves outputting the data as text from P1, parsing that text back to an integer in P2, and proceeding from there. For example:
P1.hs:
module Main where
main = do
print 5
P2.hs:
module Main where
main = fmap manipulateData getLine >>= print
where
manipulateData = (+ 1) . (read :: String -> Int)
Output:
$ (stack exec p1) | (stack exec p2)
6
I'd like to use standard i/o to send an integer without treating it as text, if possible. I'm assuming this still requires some sort of parsing to work, but I'm hoping it's possible to parse the data as binary and get a faster program.
Does Haskell have any way to make this straightforward? Since I am going from one fundamental Haskell datatype (Int) to the same type again with a pass through standard i/o in the middle, I'm wondering if there is an easy solution that doesn't require writing a custom binary parser (which I don't know how to do). Can anyone provide such a method?
Here is the code that I ended up with:
module Main where
import qualified Data.ByteString.Lazy as BS
import qualified Data.Binary as B
main :: IO ()
main = do
dat <- BS.getContents
print $ (B.decode dat :: Int) + 1
The other program uses similar imports and outputs 5 with the following line:
BS.putStr $ B.encode (5 :: Int)
The resulting programs can be piped together, and the resulting program behaves as required.

Dealing with read no parse error for lists

Hello can someone please explain me how can you deal with failed computations (in our case parsings) in Haskell when performed in a list,retrieving the successful elements?
The error i get is
main: Prelude.read: no parse and that stops all the list from being processed
I am using a forM over a collection of Text , and for each element i am using a read::String->Double for the result value.
Currently the parsing fails at the first element and i can not parse the remaining elements.How can i make single elements "fail-able" but still get partial results ( for the elements of the list that could be parsed) ?
Example :Input: ["asta","1.23","2.44"]
Desired Output:[1.23,2.44]
import qualified Data.Text as T
parseDfile::[T.Text]->IO [Maybe Double]
parseDfile []=do
return [Nothing]
parseDfile lines = forM lines $ \line ->
do
Prelude.putStrLn ("line value:"++(T.unpack line))
let value = (read::String->Double) . T.unpack $ //fails here for first element
print .show $ value
return (Just value)
P.SDo i have to define a method using the Maybe monad separately only for that one line of code ?
The Text.Read library also has a function called readMaybe that returns a Maybe a instead of just an a like read does.
In the case that you're not sure whether or not a string can be parsed, you clearly want a Maybe a. Now you need to deal with the Maybe though, however the Maybe monad has tons of functions that do exactly what you need.
For more complicated parsing you could look into the Haskell ParseLib which is really good. However it might be a little overkill if you're not trying to parse more than your example.

Parsing simple markup language with Haskell

I'm trying to implement a very simple markup language. I have an intermediate representation that looks like:
data Token = Str Text
| Explode Text
type Rep = [Token]
So, the idea is to turn an arbitrary text of the form:
The quick brown %%fox%% %%jumps%% over the %%lazy%% dog.
into:
[Str "The quick brown", Explode "fox", Explode "jumps", Str "over the", Explode "lazy", Str "dog"]
for further processing. Also, it is important that we treat:
%%fox%% %%jumps%%
differently than
%%fox jumps%%
The latter should (Explode "fox jumps")
I tried to implement this using attoparsec, but I don't think I have the tools I need. But I'm not so good with parsing theory (I studied math, not CS). What kind of grammar is this? What kind of parser combinator library should I use? I considered using Parsec with a stateful monad transformer stack to keep track of the context. Does that sound sensible?
You can take the cheap and easy way, without a proper parser. The important thing to recognise is that this grammar is actually fairly simple – it has no recursion or such. It is just a flat listing of Strs and Explodes.
The easy way
So we can start by breaking the string down into a list containing the text and the separators as separate values. We need a data type to separate the separators (%%) from actual text (everything else.)
data ParserTokens = Sep | T Text
Breaking it down
Then we need to break the list into its constituents.
tokenise = intersperse Sep . map T . Text.splitOn "%%"
This will first split the string on %%, so in your example it'll become
["The quick brown ","fox"," ","jumps"," over the ","lazy"," dog."]
then we map T over it, to turn it from a [Text] to a [ParserTokens]. Finally, we intersperse Sep over it, to reintroduce the %% separators but in a shape that's easier to deal with. The result is, in your example,
[T "The quick brown ",Sep,T "fox",Sep,T " ",Sep,T "jumps",Sep,T " over the ",Sep,T "lazy",Sep,T " dog."]
Building it up
With this done, all that remains is parsing this thing into the shape you want it. Parsing this amounts to finding the 1-2-3 punch of Sep–T "something"–Sep and replacing it with Explode "something". We write a recursive function to do this.
construct [] = []
construct (T s : rest) = Str s : construct rest
construct (Sep : T s : Sep : rest) = Explode s : construct rest
construct _ = error "Mismatched '%%'!"
This converts T s to Str s and the combination of separators and a T s into an Explode s. If the pattern matching fails, it's because there were a stray separator somewhere, so I've just set it to crash the program. You might want better error handling there – such as wrapping the result in Either String or something similar.
With this done, we can create the function
parseTemplate = construct . tokenise
and in the end, if we run your example through parseTemplate, we get the expected result
[Str "The quick brown ",Explode "fox",Str " ",Explode "jumps",Str " over the ",Explode "lazy",Str " dog."]
For such simple parser even Attoparsec seems to be overkill:
parse = map (\w -> case w of
'%':'%':expl -> Explode $ init $ init expl
str -> Str str) . words
Of course, this code needs some sanity checks for Explode case.
This doesn't handle whitespace the way you specified, but it should get you on the right track.
parseMU = zipWith ($) (cycle [Str,Explode]) . splitps where
splitps :: String -> [String]
splitps [] = [[]]
splitps ('%':'%':r) = [] : splitps r
splitps (c:r) = let
(a:r') = splitps r
in ((c:a):r')

Recursive list-constructing parser in Opa

I'd like to write a parser for hashtags. I have been reading the blog
entries on parsing on the opa blog, but they didn't cover recursive
parsers and constructions of lists a lot.
Hashtags are used by some social networks (Twitter, Diaspora*)
to tag a post. They consist of a hash sign (#) and an alphanumeric
string such as "interesting" or "funny". One example of a post using
hashtags:
Oh #Opa, you're so #lovely! (Are you a relative of #Haskell?)
Parsing that would result in ["Opa", "lovely", "Haskell"].
I have tried to do it, but it doesn't quite what I want. (It could
either only parse one hashtag and nothing else, would fail in an endless
loop or fail because there was input it didn't understand...)
Additionally, here is a Haskell version that implements it.
To begin with a remark: by posing question in Haskell-terms you're effectively looking for somebody who knows Opa and Haskell hence decreasing chances of finding a person to answer the question ;). Ok, I'm saying it half jokingly as your comments help a lot but still I'd rather see the question phrased in plain English.
I think a solution keeping the structure of the Haskell one would be something like this:
parse_tags =
hashtag = parser "#" tag=Rule.alphanum_string -> tag
notag = parser (!"#" .)* -> void
Rule.parse_list_sep(true, hashtag, notag)
Probably the main 'trick' is to use the Rule.parse_list_sep function to parse a list. I suggest you take a look at the implementation of some functions in the Rule module to get inspiration and learn more about parsing in Opa.
Of course I suggest testing this function, for instance with the following code:
_ =
test(s) =
res =
match Parser.try_parse(parse_tags, s) with
| {none} -> "FAILURE"
| {some=tags} -> "{tags}"
println("Parsing '{s}' -> {res}")
do test("#123 #test #this-is-not-a-single-tag, #lastone")
do test("#how#about#this?")
void
which will give the following output:
Parsing '#123 #test #this-is-not-a-single-tag, #lastone' -> [123, test, this, lastone]
Parsing '#how#about#this?' -> FAILURE
I suspect that you will need to fine tune this solution to really conform to what you want but it should give you a good head start (I hope).
The following work, just using plain parsers
hashtag = parser "#" tag=Rule.alphanum_string -> tag
list_tag = parser
| l=((!"#" .)* hashtag -> hashtag)* .* -> l
parsetag(s) = Parser.parse(list_tag, s)
do println("{parsetag("")}")
do println("{parsetag("aaabbb")}")
do println("{parsetag(" #tag1 #tag2")}")
do println("{parsetag("#tag1 #tag2 ")}")
do println("{parsetag("#tag1#tag2 ")}")

Haskell -> After parsing how to work with strings

Hello
after doing the parsing with a script in Haskell I got a file with the 'appearance' of lists of strings. However when I call the file content with the function getContents or hGetContents, ie, reading the contents I get something like: String with lines (schematically what I want is: "[" aaa "," bbb "" ccc "]" -> ["aaa", "bbb" "ccc"]). I have tried with the read function but without results. I need to work with these lists of strings to concatenating them all in a single list.
I'm using the lines function, but I think it only 'works' one line at a time, doesn't it?
What I need is a function that verify if an element of a line is repeted on other line. If I could have a list of a list of strings it could be easier (but what I have is a line of a string that looks like a list of strings)
Regards
Thanks.
I have tried with the read function but without results
Just tested, and it works fine:
Prelude> read "[\"aaa\",\"bbb\",\"ccc\"]" :: [String]
["aaa","bbb","ccc"]
Note that you need to give the return type explicitly, since it can't be determined from the type of the argument.
I think the function you are looking for is the lines function from Data.List (reexported by the Prelude) that breaks up a multi-line string into a list of strings.
in my understanding, what you can do is
create a function that receives a list of lists, each list is a line of the entire string, of the argument passed in, and checks if a element of a line occurs in other line.
then, this function passes the entire string, separated by lines using [lines][1].

Resources