提问人:mandark 提问时间:8/5/2017 更新时间:8/5/2017 访问量:128
实现“m (t a) -> (a -> m (t b)) -> m (t b)” 的惯用方法 [重复]
Idiomatic way to implement "m (t a) -> (a -> m (t b)) -> m (t b)" [duplicate]
问:
函数 () 具有以下签名:bind
>>=
m a -> (a -> m b) -> m b
但是,我想要一个带有签名的函数:
m (t a) -> (a -> m (t b)) -> m (t b)
具体来说,我有一个函数,它给定一个 Integer,它返回 IO 中的整数列表:
f :: Int -> IO [Int]
但我想将它应用于一个,我不能使用常规绑定函数,因为它被包装在两个容器中,即 IO 中包含的列表。在 hoogle 上搜索无济于事。IO of list of Integers
我正在使用以下方法来实现这一点:
假设该函数的实现是:
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 中实现这一点?
答:
1赞
rampion
8/5/2017
#1
惯用的解决方案是使用:Data.Functor.Compose
data Compose f g a = Compose { getCompose :: f (g a) }
由于您要查找的函数在 monad 时实现起来很简单: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)
正如这个答案所解释的那样,这还不够
对于 S 和 be s,他们还需要通勤:f
g
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
(一般来说,f
是单子和 g
是可遍历
的是不够的)
评论
f'
f''
f
do
>>=
fmap