How can I convert IO ByteString to IO String - haskell

I know how to convert a ByteString to a String with unpack but I'm struggling to figure out how to convert an IO ByteString (which is what I get back from the fetchHeader function in HaskellNet) to an IO String. I'm basically trying to do something like this
getAllHeadersForMessageUID :: IMapConnection -> UID -> IO String
getAllHeadersForMessageUID connection uid = do
headers <- fetchHeader connection uid
return (headers >>= BS.unpack)
The error message doesn't make sense to me
Couldn't match expected type ‘[BS.ByteString]’
with actual type ‘BS.ByteString’
In the first argument of ‘(>>=)’, namely ‘headers’
In the first argument of ‘return’, namely ‘(headers >>= BS.unpack)
I don't know why a list of ByteString is expected.

Try using return $ BS.unpack headers instead of return (headers >>= BS.unpack).
Or try return $ map BS.unpack headers if headers is a list of ByteStrings.
Besides the fact that it happens to type check (and I'm assuming BS.unpack headers works), here's a way to think about things:
headers is a pure value
BS.unpack is a pure function
headers >>= ... doesn't make sense because the LHS of >>= needs to be a monadic computation
... >>= BS.unpack doesn't make sense because the RHS of >>= needs to be a function which produces a monadic computation
BS.unpack headers is the string we want to return, but it's a pure value
we therefore use return to promote the pure value to a monadic computation
Update:
The following code shows that if fetchHeader has type IO [BS.ByteString], then your code will type check:
import Data.ByteString.Char8 as BS
fetchHeader :: IO [BS.ByteString] -- this works
-- fetchHeader :: IO BS.ByteString -- this doesn't
fetchHeader = undefined
foo :: IO String
foo = do
headers <- fetchHeader
return $ headers >>= BS.unpack
On the other hand, if you change its type to IO BS.ByteString you get the error you encountered.
Update 2:
Interestingly enough, when headers is a list of ByteStrings, the expression headers >>= BS.unpack does make sense and is equivalent to:
concat $ map BS.unpack headers

User5402's answer assumes the ByteString is pure ASCII (which is OK if you are the only person using your code, but there are several reasons why it's a bad idea if you intend to share it)
If the ByteString is encoded with UTF-8: you can convert it to String like this:
import qualified Codec.Binary.UTF8.String as UTF8
foo b = do
bs <- b
return $ UTF8.decode $ unpack bs
I'm not sure how to deal with other encodings such as windows codepages (other than by setting the encoding of a handle, which isn't applicable here).

Related

Monad transformers with IO and Maybe

I am trying to stack up IO and Maybe monads but either I don't understand monad transformers well enough or this is not possible using transformers. Can some one help me understand this?
f :: String -> Maybe String
main :: IO ()
main = do
input <- getLine -- IO String
output <- f input -- Maybe String (Can't extract because it is IO do block)
writeFile "out.txt" output -- gives error because writeFile expects output :: String
In the above simplified example, I have a function f that returns a Maybe String and I would like to have a neat way of extracting this in the IO do block. I tried
f :: String -> MaybeT IO String
main :: IO ()
main = do
input <- getLine -- IO String
output <- runMaybeT (f input) -- Extracts output :: Maybe String instead of String
writeFile "out.txt" output -- gives error because writeFile expects output :: String
which lets me extract the Maybe String out in the second line of do block but I need to extract the string out of that. Is there a way to do this without using case?
Let's stick for a moment with your first snippet. If f input is a Maybe String, and you want to pass its result to writeFile "out.txt", which takes a String, you need to deal with the possibility of f input being Nothing. You don't have to literally use a case-statement. For instance:
maybe from the Prelude is case analysis packaged as a function;
fromMaybe from Data.Maybe lets you easily supply a default value, if that makes sense for your use case;
traverse_ and for_ from Data.Foldable could be used to silently ignore Nothing-ness:
for_ (f input) (writeFile "out.txt") -- Does nothing if `f input` is `Nothing`.
Still, no matter what you choose to do, it will involve handling Nothing somehow.
As for MaybeT, you don't really want monad transformers here. MaybeT IO is for when you want something like a Maybe computation but in which you can also include IO computations. If f :: String -> Maybe String already does what you want, you don't need to add an underlying IO layer to it.

Haskell converting [Char] to Char

I'm working on a Haskell program that uses whte Network.Wai and Network.Socket.Internal modules. In this program, I have a function, defined like so:
prepareIp :: Request -> [([Char], [Char])]
prepareIp req = [("Remote", head $ splitOn ":" $ show $ remoteHost req)]
Originally, I made this a monadic expression (mostly for readability and clarity), written:
prepareIp :: Request -> [([Char], [Char])]
prepareIp req = do
ip <- head $ splitOn ":" $ show $ remoteHost req
[("Remote", ip)]
While the former implementation does work properly, the monadic one threw an error I can't wrap my head around: its output type was not [([Char], [Char])], but [([Char], Char)] -- the value ip was, for some reason, being turned into a single character rather than a string!
I also tried prototyping this in GHCi and type-checking using the module references as well as :t in GHCi, but to no avail, and I still don't know what caused this error.
Can anyone clue me in on why this type conflict is happening?
The reason why you're seeing that error is because you're trying to shove everything into a monad when it doesn't need to be. To illustrate, adding explicit type signatures everywhere and swapping [] for m:
getHostIp :: Request -> m []
getHostIp req = head $ splitOn ":" $ remoteHost req
prepareIp :: Request -> m ([Char], [Char])
prepareIp req = do
ip <- (getHostIp req :: m Char)
[("Remote" :: [Char], ip :: [Char])]
Whenever you see <-, the right side has to have some type like m a where m is some monadic type and a is whatever the result of that monadic action is. Then, then left side of the <- has type a. Here you've used <- to try to get the value out of a [Char], when you really just want the value of that [Char] completely. A let is appropriate here, and do notation is superfluous. Since you're also returning only a single value, I'd recommend just returning (String, String) instead of [(String, String)]:
prepareIp :: Request -> (String, String)
prepareIp req =
let ip = getHostIp req
in ("Remote", ip)

Replace nested pattern matching with "do" for Monad

I want to simplify this code
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Network.HTTP.Types
import Data.Text
getJSON :: String -> IO (Either String Value)
getJSON url = eitherDecode <$> simpleHttp url
--------------------------------------------------------------------
maybeJson <- getJSON "abc.com"
case maybeJson of
Right jsonValue -> case jsonValue of
(Object jsonObject) ->
case (HashMap.lookup "key123" jsonObject) of
(Just (String val)) -> Data.Text.IO.putStrLn val
_ -> error "Couldn't get the key"
_ -> error "Unexpected JSON"
Left errorMsg -> error $ "Error in parsing: " ++ errorMsg
by using do syntax for Monad
maybeJson <- getJSON "abc.com/123"
let toPrint = do
Right jsonValue <- maybeJson
Object jsonObject <- jsonValue
Just (String val) <- HashMap.lookup "key123" jsonObject
return val
case toPrint of
Just a -> Data.Text.IO.putStrLn a
_ -> error "Unexpected JSON"
And it gave me 3 errors:
src/Main.hs:86:19:
Couldn't match expected type `Value'
with actual type `Either t0 (Either String Value)'
In the pattern: Right jsonValue
In a stmt of a 'do' block: Right jsonValue <- maybeJson
src/Main.hs:88:19:
Couldn't match expected type `Value' with actual type `Maybe Value'
In the pattern: Just (String val)
In a stmt of a 'do' block:
Just (String val) <- HashMap.lookup "key123" jsonObject
src/Main.hs:88:40:
Couldn't match type `Maybe' with `Either String'
Expected type: Either String Value
Actual type: Maybe Value
Even when I replace
Just (String val) <- HashMap.lookup "key123" jsonObject
with
String val <- HashMap.lookup "key123" jsonObject
I'm getting another similar error about Either:
Couldn't match type `Maybe' with `Either String'
Expected type: Either String Value
Actual type: Maybe Value
In the return type of a call of `HashMap.lookup'
In a stmt of a 'do' block:
String val <- HashMap.lookup "key123" jsonObject
How do I fix those errors?
You can't easily simplify that into a single block of do-notation, because each case is matching over a different type. The first is unpacking an either, the second a Value and the third a Maybe. Do notation works by threading everything together through a single type, so it's not directly applicable here.
You could convert all the cases to use the same monad and then write it all out in a do-block. For example, you could have helper functions that do the second and third pattern match and produce an appropriate Either. However, this wouldn't be very different to what you have now!
In fact, if I was going for this approach, I'd just be content to extract the two inner matches into their own where variables and leave it at that. Trying to put the whole thing together into one monad just confuses the issue; it's just not the right abstraction here.
Instead, you can reach for a different sort of abstraction. In particular, consider using the lens library which has prisms for working with nested pattern matches like this. It even supports aeson nateively! Your desired function would look something like this:
decode :: String -> Maybe Value
decode json = json ^? key "key123"
You could also combine this with more specific prisms, like if you're expecting a string value:
decode :: String -> Maybe String
decode json = json ^? key "key123" . _String
This takes care of parsing the json, making sure that it's an object and getting whatever's at the specified key. The only problem is that it doesn't give you a useful error message about why it failed; unfortunately, I'm not good enough with lens to understand how to fix that (if it's possible at all).
So every line in a do expression for a Monad must return a value in that Monadic type. Monad is a typeclass here, not a type by itself. So putting everything in a do Monad is not really a sensible statement.
You can try your code with everything wrapped in a Maybe monad.
Assuming you've fetched your JSON value:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Network.HTTP
import qualified Data.Map as M
import Control.Applicative
import qualified Data.HashMap.Strict as HM
--------------------------------------------------------------------
main = do
maybeJson <- return $ toJSON (M.fromList [("key123","value")] :: M.Map String String)
ioVal <- return $ do -- The Maybe monad do expression starts here
maybeJson <- Just maybeJson
jsonObject <- case maybeJson of
Object x -> Just x
_ -> Nothing
val <- HM.lookup "key123" jsonObject
return val
putStrLn $ show ioVal
Once we start working in the Maybe monad, every expression must return a Maybe Something value. The way the Maybe monad works is that anything that is a Just something comes out as a pure something that you can work with, but if you get a Nothing, the rest of the code will be skipped and you'll get a Nothing.
This property of falling through is unique to the Maybe monad. Different monads behave differently.
You should read up more about Monads and the IO monad here: http://www.haskell.org/haskellwiki/Introduction_to_IO
You should read more about monads and what they really help you do:
http://learnyouahaskell.com/a-fistful-of-monads
(You should work through the previous chapters and then get to this chapter. Once you do, you'll have a pretty solid understanding of what is happening).
I also think your HTTP request is screwed up. Here's an example of a POST request that you can use.
import qualified Network.HTTP as H
main = do
postData <- return $ H.urlEncodeVars [("someVariable","someValue")]
request <- return $ H.postRequestWithBody "http://www.google.com/recaptcha/api/verify" "application/x-www-form-urlencoded" postData
putStrLn $ show request
-- Make the request
(Right response) <- H.simpleHTTP request
-- Print status code
putStrLn $ show $ H.rspCode response
-- Print response
putSrLn $ show $ H.rspBody response
UPDATED:
Use the following to help you get a JSON value:
import qualified Data.ByteString.Lazy as LC
import qualified Data.ByteString.Char8 as C
import qualified Data.Aeson as DA
responseBody <- return $ H.rspBody response
responseJSON <- return (DA.decode (LC.fromChunks [C.pack responseBody]) :: Maybe DA.Value)
You'll have to make a request object to make a request. There are quite a few helpers. I meant the post request as the most generic case:
http://hackage.haskell.org/package/HTTP-4000.0.5/docs/Network-HTTP.html
Since you are in the IO monad, all the <- are going to assume that you are dealing with IO operations. When you write
do
Right jsonValue <- maybeJson
Object jsonObject <- jsonValue
you are saying that jsonValue must be an IO action just like maybeJson. But this is not the case! jsonValue is but a regular Either value. The silution here would ge to use a do-block let instead of a <-:
do
Right jsonValue <- maybeJson
let Object jsonObject = jsonValue
However, its important to note that in both versions of your code you are using an irrecoverable error to abort your program if the JSON parsing fails. If you want to be able to collect errors, the basic idea would be to convert your values to Either (and then use the monad instance for Either to avoid having lots of nested case expressions)

After reading a file I have IO [Char], but I need [IO Char]

I have a file number.txt which contains a large number and I read it into an IO String like this:
readNumber = readFile "number.txt" >>= return
In another function I want to create a list of Ints, one Int for each digit…
Lets assume the content of number.txt is:
1234567890
Then I want my function to return [1,2,3,4,5,6,7,8,9,0].
I tried severall versions with map, mapM(_), liftM, and, and, and, but I got several error messages everytime, which I was able to reduce to
Couldn't match expected type `[m0 Char]'
with actual type `IO String'
The last version I have on disk is the following:
module Main where
import Control.Monad
import Data.Char (digitToInt)
main = intify >>= putStrLn . show
readNumber = readFile "number.txt" >>= return
intify = mapM (liftM digitToInt) readNumber
So, as far as I understand the error, I need some function that takes IO [a] and returns [IO a], but I was not able to find such thing with hoogle… Only the other way round seemes to exist
In addition to the other great answers here, it's nice to talk about how to read [IO Char] versus IO [Char]. In particular, you'd call [IO Char] "an (immediate) list of (deferred) IO actions which produce Chars" and IO [Char] "a (deferred) IO action producing a list of Chars".
The important part is the location of "deferred" above---the major difference between a type IO a and a type a is that the former is best thought of as a set of instructions to be executed at runtime which eventually produce an a... while the latter is just that very a.
This phase distinction is key to understanding how IO values work. It's also worth noting that it can be very fluid within a program---functions like fmap or (>>=) allow us to peek behind the phase distinction. As an example, consider the following function
foo :: IO Int -- <-- our final result is an `IO` action
foo = fmap f getChar where -- <-- up here getChar is an `IO Char`, not a real one
f :: Char -> Int
f = Data.Char.ord -- <-- inside here we have a "real" `Char`
Here we build a deferred action (foo) by modifying a deferred action (getChar) by using a function which views a world that only comes into existence after our deferred IO action has run.
So let's tie this knot and get back to the question at hand. Why can't you turn an IO [Char] into an [IO Char] (in any meaningful way)? Well, if you're looking at a piece of code which has access to IO [Char] then the first thing you're going to want to do is sneak inside of that IO action
floob = do chars <- (getChars :: IO [Char])
...
where in the part left as ... we have access to chars :: [Char] because we've "stepped into" the IO action getChars. This means that by this point we've must have already run whatever runtime actions are required to generate that list of characters. We've let the cat out of the monad and we can't get it back in (in any meaningful way) since we can't go back and "unread" each individual character.
(Note: I keep saying "in any meaningful way" because we absolutely can put cats back into monads using return, but this won't let us go back in time and have never let them out in the first place. That ship has sailed.)
So how do we get a type [IO Char]? Well, we have to know (without running any IO) what kind of IO operations we'd like to do. For instance, we could write the following
replicate 10 getChar :: [IO Char]
and immediately do something like
take 5 (replicate 10 getChar)
without ever running an IO action---our list structure is immediately available and not deferred until the runtime has a chance to get to it. But note that we must know exactly the structure of the IO actions we'd like to perform in order to create a type [IO Char]. That said, we could use yet another level of IO to peek at the real world in order to determine the parameters of our action
do len <- (figureOutLengthOfReadWithoutActuallyReading :: IO Int)
return $ replicate len getChar
and this fragment has type IO [IO Char]. To run it we have to step through IO twice, we have to let the runtime perform two IO actions, first to determine the length and then second to actually act on our list of IO Char actions.
sequence :: [IO a] -> IO [a]
The above function, sequence, is a common way to execute some structure containing a, well, sequence of IO actions. We can use that to do our two-phase read
twoPhase :: IO [Char]
twoPhase = do len <- (figureOutLengthOfReadWithoutActuallyReading :: IO Int)
putStrLn ("About to read " ++ show len ++ " characters")
sequence (replicate len getChar)
>>> twoPhase
Determining length of read
About to read 22 characters
let me write 22 charac"let me write 22 charac"
You got some things mixed up:
readNumber = readFile "number.txt" >>= return
the return is unecessary, just leave it out.
Here is a working version:
module Main where
import Data.Char (digitToInt)
main :: IO ()
main = intify >>= print
readNumber :: IO String
readNumber = readFile "number.txt"
intify :: IO [Int]
intify = fmap (map digitToInt) readNumber
Such a function can't exists, because you would be able to evaluate the length of the list without ever invoking any IO.
What is possible is this:
imbue' :: IO [a] -> IO [IO a]
imbue' = fmap $ map return
Which of course generalises to
imbue :: (Functor f, Monad m) => m (f a) -> m (f (m a))
imbue = liftM $ fmap return
You can then do, say,
quun :: IO [Char]
bar :: [IO Char] -> IO Y
main = do
actsList <- imbue quun
y <- bar actsLists
...
Only, the whole thing about using [IO Char] is pointless: it's completely equivalent to the much more straightforward way of working only with lists of "pure values", only using the IO monad "outside"; how to do that is shown in Markus's answer.
Do you really need many different helper functions? Because you may write just
main = do
file <- readFile "number.txt"
let digits = map digitToInt file
print digits
or, if you really need to separate them, try to minimize the amount of IO signatures:
readNumber = readFile "number.txt" --Will be IO String
intify = map digitToInt --Will be String -> [Int], not IO
main = readNumber >>= print . intify

Is there a way to unwrap a type from an IO monad?

I have this very simple function
import qualified Data.ByteString.Lazy as B
getJson :: IO B.ByteString
getJson = B.readFile jsonFile
readJFile :: IO (Maybe Response)
readJFile = parsing >>= (\d ->
case d of
Left err -> return Nothing
Right ps -> return (Just ps))
where parsing = fmap eitherDecode getJson :: IO (Either String Response)
where jsonFile is a path to a file on my harddrive (pardon the lack of do-notation, but I found this more clear to work with)
my question is; is there a way for me to ditch the IO part so I can work with the bytestring alone?
I know that you can pattern match on certain monads like Either and Maybe to get their values out, but can you do something similar with IO?
Or voiced differently: is there a way for me to make readJFile return Maybe Response without the IO?
To expand on my comments, here's how you can do it:
getJson :: IO B.ByteString
getJson = B.readFile jsonFile -- as before
readJFile :: B.ByteString -> Maybe Response -- look, no IO
readJFile b = case eitherDecode b of
Left err -> Nothing
Right ps -> Just ps
In the end, you combine everything in one IO action again:
getAndProcess :: IO (Maybe Response)
getAndProcess = do
b <- getJson
return (readJFile b)
You never need to "drag a monad" through any functions, unless they all need to actually do IO. Just lift the entire chain into the monad with fmap (or liftM / liftM2 / ...).
For instance,
f1 :: B.ByteString -> K
f2 :: K -> I
f3 :: K -> J
f4 :: I -> J -> M
and your entire thing is supposed to be like
m :: M
m = let k = "f1 getJson"
in f4 (f2 k) (f3 k)
The you can simply do
m = fmap (\b -> let k = f1 b
in f4 (f2 k) (f3 k) )
getJson
Incidentally, this might look nicer with do notation:
m = do
b <- getJson
return $ let k = f1 b
in f4 (f2 k) (f3 k)
Concerning you edit and the question
is there a way for me to make readJFile return Maybe Response without the IO?
No, that can't possibly work, because readJFile does need to do IO. There's no way escaping from the IO monad then, that's the whole point of it! (Well, there is unsafePerformIO as Ricardo says, but this is definitely not a valid application for it.)
If it's the clunkiness of unpacking Maybe values in the IO monad, and the signatures with parens in them, you may want to looks at the MaybeT transformer.
readJFile' :: MaybeT IO Response
readJFile' = do
b <- liftIO getJson
case eitherDecode b of
Left err -> mzero
Right ps -> return ps
No, there is no safe way to get a value out of the IO monad. Instead you should do the work inside the IO monad by applying functions with fmap or bind (>>=). Also you should use decode instead of eitherDecode when you want your result to be in Maybe.
getJson :: IO B.ByteString
getJson = B.readFile jsonFile
parseResponse :: B.ByteString -> Maybe Response
parseResponse = decode
readJFile :: IO (Maybe Response)
readJFile = fmap parseResponse getJSON
You could also use do notation if that is clearer to you:
readJFile :: IO (Maybe Response)
readJFile = do
bytestring <- getJson
return $ decode bytestring
Note that you dont even need the parseResponse function since readJFile specifies the type.
In general, yes, there is a way. Accompanied by a lot of "but", but there is. You're asking for what it's called an unsafe IO operation: System.IO.Unsafe. It's used to write wrappers when calling to external libraries usually, it's not something to resort to in regular Haskell code.
Basically, you can call unsafePerformIO :: IO a -> a which does exactly what you want, it strips out the IO part and gives you back wrapped value of type a. But, if you look at the documentation, there are a number of requirements which you should guarantee yourself to the system, which all end up in the same idea: even though you performed the operation via IO, the answer should be the result of a function, as expected from any other haskell function which does not operate in IO: it should always have the same result without side effects, only based on the input values.
Here, given your code, this is obviously NOT the case, since you're reading from a file. You should just continue working within the IO monad, by calling your readJFile from within another function with result type IO something. Then, you'll be able to read the value within the IO wrapper (being in IO yourself), work on it, and then re-wrap the result in another IO when returning.

Resources