请记住,我从未成功理解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)实体客户))即使这有点奇怪)
答案 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文档并尝试了解正在发生的事情。