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)