I am new to Haskell and have some difficulties wrapping my head around some of it’s concepts.
While playing around with IO I wanted to flatten an IO [[String]].
An example of what I have tried:
module DatabaseTestSO where
import Database.HDBC
import Database.HDBC.MySQL
import Data.Foldable
convSqlValue :: [SqlValue] -> [String]
convSqlValue xs = [ getString x | x <- xs ]
where getString value = case fromSql value of
Just x -> x
Nothing -> "Null"
listValues :: [[SqlValue]] -> [[String]]
listValues [] = []
listValues xs = [ convSqlValue x | x <- xs ]
flatten :: [[a]] -> [a]
flatten = Data.Foldable.foldl (++) []
domains :: IO [[String]]
domains =
do conn <- connectMySQL defaultMySQLConnectInfo {
mysqlHost = "hostname",
mysqlDatabase = "dbname",
mysqlUser = "username",
mysqlPassword = "pass" }
queryDomains <- quickQuery conn "SELECT name FROM domains" []
return (listValues queryDomains)
That works with [[String]] in GHCi as expected:
*DatabaseTestSO> flatten [["blah","blab","wah"],["bloh","blob","woh"],["blih","blib","wuh"]]
["blah","blab","wah","bloh","blob","woh","blih","blib","wuh"]
but does not with IO [[String]] where I get
*DatabaseTestSO> flatten domains
<interactive>:1:9:
Couldn't match expected type `[[a0]]'
with actual type `IO [[String]]'
In the first argument of `flatten', namely `domains'
In the expression: flatten domains
In an equation for `it': it = flatten domains
I guess I can not use a function that is supposed to be pure with IO types?
Can I convert IO [[String]] to [[String]]?
How do I solve this problem correctly?
You have to realize what
IO somethingmeans. It’s not asomething, it’s an action that will return asomething(In this case,somethingis[[String]]). So, you cannot do anything with the thing that the action returns, until you perform the action, which returns that thing.You have two options to solve your problem.
Perform the action, and use the result. This is done like this:
Create a new action that takes the result of some action, and applies a function to it. The new action then returns the transformed value. This is done with the
liftMfunction in theControl.Monadmodule.PS. You might want to rename your
domainsvariable togetDomainsto clarify what it does. It’s not a pure value; it’s a monadic action that returns a pure value.