在模块中运行Persistent查询

时间:2016-06-18 20:51:42

标签: haskell yesod

请记住,我从未成功理解monad是什么,我遇到了Yesod的问题。我有一个表单,我需要在多个处理程序中使用,所以我试图在一个模块中定义它,我可以在需要时导入。该表单使用一堆未导出的函数来创建自定义字段。 当我尝试运行简单的数据库操作时,就像我习惯在我的处理程序中一样(试图获取字段的默认值),我得到以下错误:

Couldn't match expected type ‘Maybe (Entity Client)’
            with actual type ‘HandlerT site0 IO (Maybe (Entity Client))’
In a stmt of a 'do' block: runDB $ selectFirst [ClientId ==. id] []
In the expression: do { runDB $ selectFirst [ClientId ==. id] [] }
In a case alternative:
    Just id -> do { runDB $ selectFirst [ClientId ==. id] [] }

我尝试了一堆东西,使用< - 似乎没有改变任何东西。我想我可能不在正确的monad里面?我google了很多,据我了解,runDB只能在Handler monad中工作,但我不知道如何进入,如果可能的话。

我有多个Handler导入该模块,如果重要的话,调用该函数来生成AForm。

非常感谢!

编辑: 这是引发错误的函数:

getClientFromId :: Maybe (Key Client) -> Maybe (Entity Client)
getClientFromId mId = do
  case mId of
    Nothing -> Nothing
    Just id -> do
      runDB $ selectFirst [ClientId ==. id] []

更新

所以在阅读完答案后,我尝试删除签名:没有变化。 我尝试使用不同的建议签名但没有任何效果。这是我目前的情况:

getClientFromId :: Maybe (Key Client) -> Handler (Maybe (Entity Client))
getClientFromId mId = do
  case mId of
    Nothing -> return Nothing
    Just id -> do
      client <- runDB $ selectFirst [ClientId ==. id] []
      return client

我在AForm的定义中从三元组中调用它:

  <*> (fmap entityKey <$> aopt clientIdField (addIdToField "ClientIdField" (bfs ("Owner" :: Text))) (isJust mHorse ? (Just (getClientFromId $ horseClient $ fromJust mHorse)) :? Nothing))

三元不是很容易阅读,如果我弄清楚如何使所有这些工作,我可能会改变:)。 我收到了这个错误:

Couldn't match type ‘HandlerT App IO (Maybe (Entity Client))’
               with ‘Maybe (Entity Client)’
Expected type: Maybe (Entity Client)
  Actual type: Handler (Maybe (Entity Client))
In the first argument of ‘Just’, namely
  ‘(getClientFromId $ horseClient $ fromJust mHorse)’
In the first argument of ‘(:?)’, namely
  ‘(Just (getClientFromId $ horseClient $ fromJust mHorse))’
In the second argument of ‘(?)’, namely
  ‘(Just (getClientFromId $ horseClient $ fromJust mHorse))
   :? Nothing’

看着它,似乎我有正确的返回类型,除了顶部有一个“HandlerT site0 IO”。我尝试使用带&lt; - 的中间函数来删除它,但这不起作用。我猜这里我的实际问题是我不理解monad,但我看了其他有效的Yesod项目,我真的不知道我在做什么不同。

(我知道这是嵌套多个Maybes,但在我的数据库中,horseClient是一个可能的,并且表单的默认值正在等待一个Maybe,所以看起来“正常”的最终值应该是一个Maybe(Maybe)实体客户))即使这有点奇​​怪)

2 个答案:

答案 0 :(得分:1)

您将getClientId声明为纯函数,但您也调用执行I / O的runDB,因此它不能是纯函数。直观地说,这就是为什么它不进行类型检查。

我建议您在没有类型签名的情况下单独编写getClientId ,并查看GHC推断的内容。我的猜测是它会像:

Maybe (Key Client) -> Handler (Maybe (Entity Client))

这意味着你所谓的任何地方你都需要做以下事情:

mid' <- getClientFromId mid

答案 1 :(得分:0)

让我们来看看类型。

selectFirst :: (PersistEntity val, PersistEntityBackend val ~ PersistMonadBackend m) => 
               [Filter val] -> 
               [SelectOpt val] -> 
               m (Maybe (Entity val))

runDB :: YesodDB site a -> HandlerT site IO a

type YesodDB site = ReaderT (YesodPersistBackend site) (HandlerT site IO)

m中的selectFirst将为YesodDB site,这是我猜测提供数据库连接的ReaderT的别名。

我认为你的函数的正确类型应该是

Maybe (Key Client) -> HandlerT site IO (Maybe (Entity Client))

site将替换为您的Yesod实例类型。

更新

首先,这非常难看:

(isJust mHorse ? (Just (getClientFromId $ horseClient $ fromJust mHorse)) :? Nothing)

你可以这样做:

fmap (justClientFromId . horseClient) mHorse

然而,这带来了第二个问题。 justClientFromid会返回Handler包装您想要的值。

我认为主要问题源于你的第一个陈述:

Keeping in mind that I never succeded in understanding what a monad is

您应该阅读Yesod文档并尝试了解正在发生的事情。