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
要求monad
m
在类
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]