现在我一直在运行Haskell代码,我觉得我应该能够使用mapM
来使Monads的操作更整洁,但是如果我有两个类型为m (t a)
的计算,并且也许还有另一种使用t
的操作,类似于a -> t a
(通常是Maybe
)……说我有这个持久代码:
findDealership :: MonadIO m => Key Vehicle -> SqlPersistT m (Maybe (Entity Dealership))
findDealership vehicleKey = mapM selectDealership (getVehicleDealership vehicleKey)
getVehicleDealership :: MonadIO m => Key Vehicle -> SqlPersistT m (Maybe (Key Dealership))
getVehicleDealership vehicleKey =
(\x -> x >>= vehicleDealershipId . entityVal) <$> getEntity vehicleKey
selectDealership :: MonadIO m => Key Dealership -> SqlPersistT m (Maybe (Entity Dealership))
selectDealership dealershipKey = selectFirst [DealershipId ==. dealershipKey] []
如果vehicleDealershipId
是类型Maybe (Key Dealership)
的字段,则上面的代码将无法编译,并且我无法计算出>>=
和{{1}的正确组合}的...。我觉得这个问题有点像一个mapM
所解决的问题,只是那里存在另一层单子。。。你可以以mapM
结尾需要将内部类型完全弄平...
上述代码的错误输出:
SqlPersistT m (Maybe (Maybe (Maybe (Key Dealership))))
和:
• Couldn't match type ‘Control.Monad.Trans.Reader.ReaderT
SqlBackend m0’
with ‘Maybe’
Expected type: SqlPersistT m (Maybe (Entity Dealership))
Actual type: Control.Monad.Trans.Reader.ReaderT
SqlBackend
m
(Control.Monad.Trans.Reader.ReaderT
SqlBackend m0 (Maybe (Entity Dealership)))
• In the expression:
mapM selectDealership $ getVehicleDealership vehicleKey
In an equation for ‘findDealership’:
findDealership vehicleKey
= mapM selectDealership $ getVehicleDealership vehicleKey
|
46 | findDealership vehicleKey = mapM selectDealership $ getVehicleDealership vehicleKey
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
答案 0 :(得分:3)
当您要展平多个Maybe
时,可以使用join
。它适用于任何Monad
,但最常用于Maybe
。
getVehicleDealership :: MonadIO m => Key Vehicle -> SqlPersistT m (Maybe (Key Dealership))
getVehicleDealership vehicleKey =
join . fmap (vehicleDealershipId . entityVal) <$> getEntity vehicleKey
mapM
(又称traverse
)在许多情况下很有用,但我认为它在这里并不适用。 Maybe
的显示顺序无关紧要,而您想要的是SqlPersistT m (Maybe a)
,而不是Maybe (SqlPersistT m a)
。
答案 1 :(得分:0)
我现在意识到,我在这里想要的是MaybeT
。
我的示例可以像这样使用 MaybeT
重写:
findDealership :: MonadIO m => Key Vehicle -> SqlPersistT m (Maybe (Entity Dealership))
findDealership vehicleKey = runMaybeT $ do
dealershipKey <- MaybeT (getVehicleDealership vehicleKey)
selectDealership dealershipKey
getVehicleDealership :: MonadIO m => Key Vehicle -> SqlPersistT m (Maybe (Key Dealership))
getVehicleDealership vehicleKey = runMaybeT $ do
vehicleEntity <- MaybeT (getEntity vehicleKey)
hoistMaybe $ vehicleDealershipId (entityVal vehicleEntity)
selectDealership :: MonadIO m => Key Dealership -> SqlPersistT m (Maybe (Entity Dealership))
selectDealership dealershipKey =
selectFirst [DealershipId ==. dealershipKey] []