2

我正在尝试将这个Heist 教程和这个postgresql-simple 教程结合起来。

我尝试对此进行不同的变体。

splice :: C.Splice IO  
splice =  do  
  projects <- query_ "SELECT * FROM projects"  
  C.manyWithSplices C.runChildren projectSplice $ return (projects :: [Project])  
  where  
    projectSplice = do  
      "title" ## (C.pureSplice . C.textSplice $ title)  
      "description" ## (C.pureSplice . C.textSplice $ description)  

但我一直收到这个错误。

No instance for (HasPostgres (HeistT IO IO))
  arising from a use of 'query_'
Possible fix:
  add an instance declaration for (HasPostgres (HeistT IO IO))
In a stmt of a 'do' block:
  projects <- query_ "SELECT * FROM projects"
In the expression:
  do { projects <- query_ "SELECT * FROM projects";
       C.manyWithSplices C.runChildren projectSplice 
       $ return (projects :: [Project]) }

我不知道如何实现该实例声明,我仍然没有完全掌握单子。我不确定我是否走在正确的轨道上。

编辑:感谢@mightybyte 的回答,我想出了这个。

projectSplice = do
  "title" ## (C.pureSplice . C.textSplice $ title)
  "description" ## (C.pureSplice . C.textSplice $ description)

splice :: C.Splice (Handler App App)
splice =  C.manyWithSplices C.runChildren projectSplice $ lift $ query_ "SELECT * FROM projects"

getHeistState heistConfig = liftIO $ either (error "Heist Init failed") id <$> (runEitherT $ initHeist heistConfig)

getBuilder heistState = maybe (error "Render template failed") fst $ C.renderTemplate heistState "database"

getAllProjectsHeist :: Handler App App ()
getAllProjectsHeist = do
  let heistConfig = HeistConfig defaultInterpretedSplices defaultLoadTimeSplices ("project" ## splice) noSplices [loadTemplates "templates"]
  heistState <- getHeistState heistConfig
  builder <- getBuilder heistState
  writeBS $ toByteString builder
4

1 回答 1

2

你可能想要更像这样的东西:

splice = do
  C.manyWithSplices C.runChildren projectSplices $ 
    lift $ query_ "SELECT * FROM projects"
  where
    projectSplices = do
      "title" ## (C.pureSplice . C.textSplice $ title)
      "description" ## (C.pureSplice . C.textSplice $ description)

这里的关键是理解类型。让我们稍微注释一下上面的结构:

splice :: Monad n => Splice n
splice = do
  foo
  C.manyWithSplices C.runChildren projectSplices $ do
    bar
    lift baz

符号 foo 与 , 具有相同的类型spliceSplice n相当于HeistT n IO Blah. 的细节对于Blah手头的讨论并不重要。如果您查找 的类型签名manyWithSplices,您会看到它返回Splice n,所以到目前为止一切看起来都不错。你似乎有runChildren并且是projectSplices正确的,所以让我们关注第三个论点manyWithSplices。再次参考 API 文档,我们看到第三个参数有 type RuntimeSplice n [a],所以这是 typebar必须有的。但这是什么RuntimeSplice东西。好吧,如果您在 API 文档中单击它,您会看到它有一个 MonadTrans 类型类的实例。如果你点击它,你会看到MonadTrans它只定义了一个函数,lift,这就是我们在这里使用的。将lift的类型签名与我们已经计算出的内容结合起来,我们可以得出baz具有类型的结论n [a]

n是你的运行时单子,HeistT n IO也是你的加载时间单子。如果您在像 Janrain 教程这样的 Snap Web 应用程序的上下文中工作,那么在您的情况下n将是Handler b b. 您指定了类型签名Splice IO,这在您的问题的上下文中不起作用,因为 IO 不是正确的单子。

于 2013-11-27T15:37:18.367 回答