Haskell 理解嵌套的Monad约束
假设我有以下类型:Haskell 理解嵌套的Monad约束,haskell,io,monads,transformation,monad-transformers,Haskell,Io,Monads,Transformation,Monad Transformers,假设我有以下类型: data Row = Row { id :: !AddressID } 具有以下内部转换功能: makeAddress :: MonadIO m => MonadError Error m => Connection -> Row -> m Address makeAddress _ Row{..} = return $ Address "Potato" 然后,我使用以下函数从数据
data Row = Row
{
id :: !AddressID
}
具有以下内部转换功能:
makeAddress :: MonadIO m => MonadError Error m => Connection -> Row -> m Address
makeAddress _ Row{..} = return $ Address "Potato"
然后,我使用以下函数从数据库中读取:
我意识到我的makeAddress
函数是不必要的复杂,这是一个最小的情况,可以从一个更大、更有效的转换函数中归结出来
但我不明白为什么它无法编译,我会想:
给定此类型:makeAddress::MonadIO m=>MonadError Error m=>Connection->Row->m Address
,则makeAddress db
的类型为MonadIO m=>MonadError Error m->Row->m Address
。给定的xs
具有类型[Row]
,映射(makeAddress db)xs
应给出[address]
考虑到内部和外部m
(在makeAddress
和findMany
中)都是MonadIO
类型类的实例,它们应该是兼容的monad
显然这是不正确的,但我不知道我的推理哪里出了问题,也不知道如何修复我的实现 concat(map f list)
要求f
返回列表。这使得map f list
可以生成一个列表列表,以concat
因此,在您的代码中,您使用makeAddress
选择m=[]
,以便map(makeAddress…)xs:[[Address]]
和concat(…:[Address]
。现在,makeAddress
要求monadm
在类MonadIO
中,但m=[]
不是,因此出现错误
试着使用类似于
...
then mapM (makeAddress db) xs
else ...
你说:
makeAddress :: MonadIO m => MonadError Error m => Connection -> Row -> m Address
当然。以及:
makeAddress db :: MonadIO m => MonadError Error m -> Row -> m
够近了。它的结尾实际上是m地址
,但我想这只是一个打字错误。以及:
map (makeAddress db) xs :: [Address]
这是你的第一个错误。您丢失了m
!事实上:
map (makeAddress db) xs :: MonadIO m => MonadError Error m => [m Address]
对这个错误的解释是我们有
concat :: [[a]] -> [a]
因此,要使[m Address]
等于[[a]]
,我们必须选择m~[]
和a~ Address
1;但是,[]
不是一个可以执行IO的monad,因此不能满足MonadIO m
约束。哎呀
您可以使用sequenceA
,而不是concat
:
sequenceA :: Applicative m => [m a] -> m [a]
-- OR, specializing,
sequenceA :: MonadIO m => MonadError m => [m Address] -> m [Address]
这个map
-sequenceA
组合非常常见,它有自己的名称:
traverse :: Applicative m => (a -> m b) -> [a] -> m [b]
如果您以前没有看过~
,您可以在回答中的任何地方用=
替换它,并且不会丢失任何重要内容
sequenceA :: Applicative m => [m a] -> m [a]
-- OR, specializing,
sequenceA :: MonadIO m => MonadError m => [m Address] -> m [Address]
traverse :: Applicative m => (a -> m b) -> [a] -> m [b]