Haskell,Snap:简单的snaplet结构.我们什么时候使用snaplet和库?

r.s*_*cky 9 haskell haskell-snap-framework

我想了解简单的snaplet结构.另外,我什么时候需要制作一个snaplet和一个简单的侧库?如果我确实需要一个如何从库中取出它?

例如,我有一堆数据库函数,我在其中包装我的SQL代码,如下所示.

data Person = Person {personName :: ByteString, personAge :: Int}

connect :: IO Connection
connect = connectSqlite3 "/somepath/db.sqlite3"

savePerson :: Person -> IO ()
savePerson p = do
c <- connect
run c "INSERT INTO persons (name, age) \
      \VALUES (?, ?)"
      [toSql (personName p), toSql (personAge p)]
commit c
disconnect c
Run Code Online (Sandbox Code Playgroud)

每个函数都会启动一个新连接并在提交后关闭连接.我想制作一个snaplet是避免每个功能连接的方法吗?在我的处理程序中,我会像这样使用它:

insertPerson :: Handler App App ()
insertPerson = do
  par <- getPostParams
  let p = top par
  liftIO $ savePerson p
where
  top m =
    Person {personName = head (m ! (B.pack "name"))
           ,personAge  = read (B.unpack (head (m ! (B.pack "age")))) :: Int
           }
Run Code Online (Sandbox Code Playgroud)

它到目前为止工作.我的问题是:我什么时候才能将库变成snaplet?我是否需要将简单的DB库转换为snaplet,以初始化连接而不是在每个函数中建立连接?

现在,如果我制作snaplet ......在Snap网站上有一个顶级sanaplet的小例子,但是没有关于如何制作你自己的简单pluggble snaplet的痕迹.

所以我在我的DB库中添加了snaplet初始化函数

dbInit :: SnapletInit b Connection
dbInit = makeSnaplet "DB" "My DB Snaplet" Nothing $ do
  dbc <- liftIO $ connectSqlite3 "/somepath/db.sqlite3"
  onUnload $ disconnect dbc
  return $ dbc
Run Code Online (Sandbox Code Playgroud)

这是正确的做法吗?这是我需要把它变成一个可插入的snaplet吗?

然后我将这个DB snaplet堆叠到主应用程序中

data App = App
  { _heist :: Snaplet (Heist App),
    _dbcon :: Snaplet (Connection)
  }

makeLens ''App

app :: SnapletInit App App
app = makeSnaplet "app" "My app" Nothing $ do
  h <- nestSnaplet "heist" heist $ heistInit "templates"
  d <- nestSnaplet "" dbcon dbInit
  addRoutes routes
  return $ App h d
Run Code Online (Sandbox Code Playgroud)

现在,我得到的只是我的请求处理程序可用的连接,对吧?所以我的经纪人变成:

insertPerson :: Handler App App ()
insertPerson = do
  par <- getPostParams
  let person = top par
  connection <- gets _dbcon
  liftIO $ savePerson connection person
where
  top m =
    Person {personName = head (m ! (B.pack "name"))
           ,personAge  = read (B.unpack (head (m ! (B.pack "age")))) :: Int
           }
Run Code Online (Sandbox Code Playgroud)

这似乎不起作用.我究竟做错了什么?这是从snaplet句柄(dbcon)中提取连接的正确方法吗?这通常是构建简单snaplet的正确方向吗?在我的情况下,我真的需要一个snaplet吗?

谢谢.

qub*_*tal 4

HandlerMonadState是:的一个实例MonadState v (Handler b v)

Handler也是 的一个实例MonadSnaplet,因此提供了该with方法:
with :: Lens v (Snaplet v') -> m b v' a -> m b v a

dbcon是一个Lens App (Snaplet Connection).

所以要到达Connection我们可以使用:
conn <- with dbcon get

如果您提供每个人都可能受益的功能,您通常会创建一个 snaplet。对于您的情况,最好利用HDBC snaplet,您可以使用它来连接到 sqlite3 数据库。

查看http://norm2782.github.com/snaplet-hdbc.html,了解有关使用 HDBC snaplet 的好教程。