Search code examples
haskelltype-systems

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?


Solution

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