Haskell converting [Char] to Char - haskell

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)

Related

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?

Language.Haskell.Interpreter: is this the right tool for the job at hand?

I have a little toy semantics for natural language, with words like:
ran :: String -> Bool
ran = (`elem` ["Bart", "Homer", "Marge"])
and:
bart :: String
bart = "Bart"
So for example, I can have (ran bart) :: Bool, and so on.
I want to write a parser which, for example takes the string "Bart ran" and returns True. I'd probably use Parsec for this.
However, the problem is being able to call functions via strings. E.g. getting from "ran" to the function ran. For this, I thought Language.Haskell.Interpreter's interpret function might be appropriate.
So my questions are:
Is this a sensible way to do what I want to do?
If so, why doesn't the following work, entered into GHCi, given a module called Grammar.hs in the same directory with ran defined as above:
let a = runInterpreter $ do
loadModules ["Grammar"]
setImports ["Prelude"]
interpret "ran" (as :: String -> Bool)
let b = do
x <- a
return $ x <*> pure "John"
b
I get the error:
"Left (WontCompile [GhcError {errMsg = "<interactive>:2:1:\n Not in scope: \8216ran\8217\n Perhaps you meant \8216tan\8217 (imported from Prelude)"}])"
which suggests that the import isn't working, and indeed, if I try something similar with a Prelude function, everything works.
Why do I get the following type error (among many others) if I try to compile the same code as in Q2, (minus the let):
No instance for MonadIO m0 arising from a use of runInterpreter
As for #2, you need to add "Grammar" to the setImports list as well:
runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
As for #3, it is because runInterpreter is monomorphic in the choice of monad to run it in:
runInterpreter :: (MonadIO m, MonadMask m)
=> InterpreterT m a
-> m (Either InterpreterError a)
So you'll need to choose a particular m by running it in e.g. IO:
main :: IO ()
main = do
ran <- runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
print $ ran <*> pure "John"
Now, as for #1, I am not convinced you need something as stupidly powerful as HInt here. You could just maintain a dictionary of String -> Bool functions keyed by a String key, something simple like a Map String (String -> Bool), and then use that to look up ran etc.

How can I convert IO ByteString to IO String

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).

Snap framework - repeated maybe tidying

I'm applying my (limited) Haskell knowledge to the Snap web framework and seeing what I can build. I'm trying to get a (possibly non-existent) parameter and parse it into an int. Obviously "Maybe" is what I'll be wanting.
In the code below AppHandler is defined as Handler App App (a monad with two levels of state I think, although I can't find anything in the tutorial now). The B8 is ByteString.Char8 and readInt returns Maybe(Int,ByteString)
The code below works, but presumably there should be a way to chain the maybe calls together (via MaybeT presumably, since I'm in a Monad already). The chaining makes particular sense because the next step will be to fetch a row from the database based on the parsed id, so of course that will return a "Maybe a" too. Clearly that's a pattern that's going to be very common.
-- Given a parameter name, return the Int it points to
-- or Nothing if there is some problem
maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
raw_param <- getParam pname
let mb_i_b = maybe (Nothing) B8.readInt raw_param
case mb_i_b of
Nothing -> return Nothing
Just (p,_) -> return $ Just p
I tried applying runMaybeT but with no real understanding of what types need changing frankly I was making random changes in the hope the error goes away. It didn't, although it changed and moved around from line to line.
I'm treating this as progress, since I'm now completely lost at a much higher level than I was when I started exploring Haskell...
Edit: walking through kosmikus' answer, hopefully I've understood it...
1 maybeIntParam :: ByteString -> AppHandler (Maybe Int)
2 maybeIntParam pname = do
3 raw_param <- getParam pname
4 return $ do
5 param <- raw_param
6 (p, _) <- B8.readInt param
7 return p
I think I was trying to inch towards this but kept trying to force getParam inside the same block as the other steps.
On line 3, the call to getParam is taking place in the AppHandler. We've got raw_param which is a Maybe ByteString. On line 5 we're in a nested do, so the binding(?) is taking place inside the Maybe monad and param will either be a ByteString or we get Nothing and the rest of the do-block will short-circuit*. Likewise on line 6, p is either an Int or we short-circuit.
All being well, on line 6, p contains an Int (say 42), and line 7 will return Just 42. Back at line 4 that becomes AppHandler (Just 42). Don't need to care what an AppHandler is at the moment - the types are all happy.
Here are some variations that also type-check and may prove of use to those trying to think this through.
maybeIntParam1 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam1 pname = do
raw_param <- getParam pname
let mb_int_param = do
param <- raw_param
(p, _) <- B8.readInt param
return p
return mb_int_param
maybeIntParam2 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam2 pname = do
return $ return 27
maybeIntParam3 :: ByteString -> AppHandler (Maybe Int)
maybeIntParam3 pname = do
return (Just 27)
The non-do variation actually seems simpler in this case. the only bit that needs thinking about is the <$> which if I'm reading right is just fmap and applies the fst to Maybe (Int,ByteString) so we can get Maybe Int.
* If I understand correctly, each subsequent line must be visited but just returns Nothing, so not actually a goto-style shortcut.
Edit2: see kosmikus' comment below - laziness + right-nesting means we don't need to evaluate each line.
You can just locally use the Maybe monad here:
maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
raw_param <- getParam pname
return $ do
param <- raw_param
(p, _) <- B8.readInt param
return p
Or if you prefer, you can write the Maybe-computations as a one-liner:
maybeIntParam :: ByteString -> AppHandler (Maybe Int)
maybeIntParam pname = do
raw_param <- getParam pname
return $ fst <$> (raw_param >>= B8.readInt)
Some of the types involved:
raw_param :: Maybe ByteString
B8.readInt :: ByteString -> Maybe (Int, ByteString)
raw_param >>= B8.readInt :: Maybe (Int, ByteString)
fst :: (Int, ByteString) -> Int
fst <$> (raw_param >>= B8.readInt) :: Maybe Int

Resources