如何有效地使用我从SQLite3和HDBC获得的嵌套monad

时间:2014-08-25 07:07:08

标签: haskell sqlite monads hdbc

我必须承认我仍然没有"那里"但是当谈到有效地与monads合作时,如果这是一个简单的问题,请原谅我。我还必须为不提供工作代码而道歉,因为这个问题与我正在进行的实际实现相关的概念更多。

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

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

或类似的东西,对吗?在我看来,使用嵌套monad的结构可能足够常见(并且非常麻烦),因为有一种标准的方法可以让我更容易使用我不知道的东西?

1 个答案:

答案 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

希望这有助于某人在这里。