【问题标题】:Run Persistent queries inside a module在模块内运行持久查询
【发布时间】:2016-06-19 19:52:03
【问题描述】:

请记住,我从未成功理解什么是单子,我对 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] [] }

我尝试了很多东西,使用

我有多个处理程序导入该模块,调用该函数以生成 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”。我尝试使用带有

(我知道这是嵌套多个 Maybe,但在我的 DB horseClient 中是一个 Maybe,并且表单的默认值正在等待一个 Maybe,因此最终值应该是一个 Maybe 似乎是“正常的”(Maybe (实体客户端))即使这有点奇​​怪)

【问题讨论】:

  • 如果您提供更多代码,我相信我们可以提供帮助。尝试构建能显示该问题的最小示例。
  • 我在原帖中添加了这个功能

标签: haskell yesod


【解决方案1】:

您将getClientId 声明为纯函数,但您还调用了执行I/O 的runDB,因此它不能是纯函数。直觉上这就是它不输入检查的原因。

我建议您单独编写getClientId没有类型签名,然后看看 GHC 会推断出什么。我的猜测是它会是这样的:

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

这意味着无论您在哪里调用它,您都需要执行以下操作:

mid' <- getClientFromId mid

【讨论】:

  • 我尝试删除签名,它没有改变任何错误。我根据当前情况更新了我的帖子
【解决方案2】:

让我们看看类型。

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)

selectFirst 中的 m 将是 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 文档并尝试了解发生了什么。

【讨论】:

  • 我尝试了这些签名,但不幸的是无法使其工作。我用我目前所在的位置更新了我的帖子。
  • fmap 的东西很酷,我改变了一切,试图弄清楚这一点,以至于我没有意识到它可能这么简单。我用这个更新了我的代码的其他部分,感谢处理程序部分,我尝试阅读一堆关于 monad 的内容,但我觉得它只是让我更加困惑,我尝试了一切,但我不明白如何打开它。我发现了多个线程,据说你不能也不应该想从 monad 中提取值,但是我应该如何使用它呢?我的表单不期待 Handler Maybe,我不知道如何强制它。
  • 我对 Yesod 了解不多,但您必须在 Handler 中创建表单,对吧?所以我认为你可能想在 Handler 中执行类似clientId &lt;- fmap (justClientFromId . horseClient) mHorse 的操作,然后将clientId 作为参数传递给创建表单的函数。
  • 是的,这就是我最终所做的,而且它有效。但这有点难看,我必须在每次调用表单生成函数之前复制我的数据库查询,复制代码不是最好的解决方案:(
猜你喜欢
  • 2015-07-14
  • 1970-01-01
  • 2012-12-24
  • 2019-06-18
  • 1970-01-01
  • 2015-05-11
  • 2021-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多