1

bind函数 ( )>>=具有签名:

m a -> (a -> m b) -> m b

但是,我想要一个带有签名的函数:

m (t a) -> (a -> m (t b)) -> m (t b)

具体来说,我有一个给定整数的函数,它返回 IO 中的整数列表:

f :: Int -> IO [Int]

但我想将它应用到一个IO of list of Integers并且我不能使用常规绑定函数,因为它被包装在两个容器中,即包含在 IO 中的列表。在hoogle上搜索没有帮助。

我正在使用以下方法来实现这一点:

假设函数的实现是:

f :: Int -> IO [Int]
f x = do
  return $ [x-10, x+10]

我正在使用两个辅助函数来获得我想要的东西:

f' :: [Int] -> IO [Int]
f' xs = do
  list <- traverse f xs
  return $ join list

f'' :: IO [Int] -> IO [Int]
f'' xs = do
  ys <- xs
  f' ys

以上工作,但我想知道是否有更好/惯用的方法来实现这个在haskell?

4

1 回答 1

1

惯用的解决方案是使用Data.Functor.Compose

data Compose f g a = Compose { getCompose :: f (g a) }

由于您正在寻找的功能是微不足道的实现时Compose f g是一个单子:

bibind :: Monad (Compose f g) => f (g a) -> (a -> f (g b)) -> f (g b)
bibind m h = getCompose (Compose m >>= Compose . h)

正如这个答案中f所解释的那样,对于和g成为s来说是不够Monad的,他们还需要通勤:

class Commute f g where
  commute :: g (f x) -> f (g x)

instance (Monad f, Monad g, Commute f g) => Monad (Compose f g) where
  return = Compose . return . return
  join = Compose .  fmap join .  join .  fmap commute . getCompose . fmap getCompose

(一般来说,成为一个单子和成为 是不够的fgTraversable

于 2017-08-04T23:06:21.727 回答