Haskell 有 3 个单子结果时的 mapM
Haskell's mapM when there are 3 monadic results
我一次又一次地将 运行 保留在 Haskell 代码中,我觉得我应该能够使用 mapM
来使对 monad 的操作更干净,但是如果我有两个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)
的字段,上面的代码将无法编译,我无法计算出 >>=
和 [= 的正确组合14=] 的....我觉得这个问题有点像 mapM
正在解决的问题,只是那里有另一个级别的 monad...你可以得到 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
和:
• Couldn't match type ‘Maybe (Key Dealership)’
with ‘Key Dealership’
Expected type: Control.Monad.Trans.Reader.ReaderT
SqlBackend m0 (Key Dealership)
Actual type: SqlPersistT m0 (Maybe (Key Dealership))
• In the second argument of ‘($)’, namely
‘getVehicleDealership vehicleKey’
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
当你想压平几个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)
。
我现在意识到,我想要的是 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] []
我一次又一次地将 运行 保留在 Haskell 代码中,我觉得我应该能够使用 mapM
来使对 monad 的操作更干净,但是如果我有两个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)
的字段,上面的代码将无法编译,我无法计算出 >>=
和 [= 的正确组合14=] 的....我觉得这个问题有点像 mapM
正在解决的问题,只是那里有另一个级别的 monad...你可以得到 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
和:
• Couldn't match type ‘Maybe (Key Dealership)’
with ‘Key Dealership’
Expected type: Control.Monad.Trans.Reader.ReaderT
SqlBackend m0 (Key Dealership)
Actual type: SqlPersistT m0 (Maybe (Key Dealership))
• In the second argument of ‘($)’, namely
‘getVehicleDealership vehicleKey’
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
当你想压平几个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)
。
我现在意识到,我想要的是 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] []