我必须承认我仍然没有"那里"但是当谈到有效地与monads合作时,如果这是一个简单的问题,请原谅我。我还必须为不提供工作代码而道歉,因为这个问题与我正在进行的实际实现相关的概念更多。
我正在攻击SQLite(3)数据库,当然希望向它发送查询并获得结果。已经在IO中,fetchAllRows
函数返回需要转换的[[SqlValue]]
。由于SQLite在文本和浮点值方面非常自由(并且Haskell在类型方面根本不自由),使用safeFromSql
进行安全转换似乎是合适的。现在,如果您设法在一个函数中完成所有这些操作,那么最终将使用该函数
myfunc :: String -> [SqlValue] -> IO [[ Either ConvertError a]]
或类似的东西,对吗?在我看来,使用嵌套monad的结构可能足够常见(并且非常麻烦),因为有一种标准的方法可以让我更容易使用我不知道的东西?
答案 0 :(得分:0)
问题似乎只能通过某些特定功能解决,然后最明显的是做语法。下面的函数解决了direct-sqlite3包访问SQLite数据库的问题(并且还插入了一个REGEXP处理程序)。
import Text.Regex.Base.RegexLike
import qualified Text.Regex.PCRE.ByteString as PCRE
import qualified Data.ByteString as BS
import Data.Text (pack,Text,append)
import Data.Text.Encoding (encodeUtf8)
import Data.Int (Int64)
import Database.SQLite3
pcreRegex :: BS.ByteString -> BS.ByteString -> IO Int64
pcreRegex reg b = do
reC <- pcreCompile reg
re <- case reC of
(Right r) -> return r
(Left (off,e) ) -> fail e
reE <- PCRE.execute re b
case reE of
(Right (Just _)) -> return (1 :: Int64)
(Right (Nothing)) -> return (0 :: Int64)
(Left (c,e)) -> fail e -- Not a good idea maybe, but I have no use for error messages.
where pcreCompile = PCRE.compile defaultCompOpt defaultExecOpt
sqlRegexp :: FuncContext -> FuncArgs -> IO ()
sqlRegexp ctx args = do
r <- fmap encodeUtf8 $ funcArgText args 0
t <- fmap encodeUtf8 $ funcArgText args 1
res <- pcreRegex r t
funcResultInt64 ctx res
getRows :: Statement -> [Maybe ColumnType] -> [[SQLData]] -> IO [[SQLData]]
getRows stmt coltypes acc = do
r <- step stmt
case r of
Done -> return acc
Row -> do
out <- typedColumns stmt coltypes
getRows stmt coltypes (out:acc)
runQuery q args columntypes dbFile = do
conn <- open $ pack dbFile
createFunction conn "regexp" (Just 2) True sqlRegexp
statement <- prepare conn q
bind statement args
res <- fmap reverse $ getRows statement (fmap Just columntypes) [[]]
Database.SQLite3.finalize statement
deleteFunction conn "regexp" (Just 2)
close conn
return $ res
希望这有助于某人在这里。