2

我不得不承认,当谈到有效地使用 monad 时,我还没有“在那里”,所以如果这是一个简单的问题,请原谅我。我还必须为没有提供工作代码而道歉,因为这个问题更多地与一个概念相关,而不是我目前正在研究的实际实现。

我正在使用 SQLite(3) 数据库,当然想向它发送查询并返回结果。已经在 IO 中,该fetchAllRows函数返回一个[[SqlValue]]需要转换的。由于 SQLite 在什么是文本和什么是浮点值方面非常自由(而 Haskell 在类型方面根本不自由),使用安全转换safeFromSql似乎是合适的。现在,如果你设法在一个函数中完成所有这些,你最终会得到这个函数

myfunc :: String -> [SqlValue] -> IO [[ Either ConvertError a]]

或类似的东西,对吧?在我看来,使用嵌套单子的结构可能足够普遍(并且足够麻烦),以至于有一种标准的方法可以让我更容易使用我不知道的方法?

4

1 回答 1

0

这个问题似乎只能通过一些特定的函数来解决,然后最明显的是 do 语法。下面的函数解决了在 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

希望这可以帮助这里的人。

于 2016-06-03T10:48:57.090 回答