我是Haskell的新手,并且在围绕其中的一些概念时遇到了一些困难。
在玩IO时,我想要展平IO [[String]]。
我尝试过的一个例子:
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)
符合预期的GHCi中的[[String]]
:
*DatabaseTestSO> flatten [["blah","blab","wah"],["bloh","blob","woh"],["blih","blib","wuh"]]
["blah","blab","wah","bloh","blob","woh","blih","blib","wuh"]
但是我没有IO [[String]]
*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
我想我不能使用一个纯粹的IO类型的函数?
我可以将IO [[String]]
转换为[[String]]
吗?
我该如何正确解决这个问题?
答案 0 :(得分:15)
你必须意识到IO something
的含义。它不是something
,而是操作会返回something
(在这种情况下,something
是[[String]]
)。因此,在执行操作返回该操作之前,您无法对操作返回的操作执行任何操作。
您有两种方法可以解决您的问题。
执行操作,并使用结果。这是这样做的:
do
ds <- domains -- Perform action, and save result in ds
return $ flatten ds -- Flatten the result ds
创建一个新操作,该操作获取某些操作的结果,并将一个函数应用于该操作。然后新操作返回转换后的值。这是通过liftM
模块中的Control.Monad
函数完成的。
import Control.Monad
-- ...
do
-- Creates a new action that flattens the result of domains
let getFlattenedDomains = liftM flatten domains
-- Perform the new action to get ds, which contains the flattened result
ds <- getFlattenedDomains
return ds
PS。您可能希望将domains
变量重命名为getDomains
以澄清它的作用。这不是一个纯粹的价值;这是一种回归纯粹价值的一元行动。
答案 1 :(得分:10)
你无法从IO中获得任何东西,所以你需要做的就是举起flatten
在其中工作。最简单的方法是fmap
- 就像map
在列表中应用函数一样,fmap
在任何Functor
实例上应用函数,例如{{1} }}
IO
在更一般的情况下,您可以使用flattenIO xs = fmap flatten xs
表示法来计算do
次计算中的内容。例如:
IO
......在这种情况下,这只是一种迂回的写作方式flattenIO xs = do ys <- xs
return (flatten ys)
。