2017-08-04 8 views
1

bind関数(>>=)が署名を有する:慣用的方法

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

しかし、Iシグネチャを持つ関数をしたい:

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

具体的には、私は整数与えられた機能を持っている、それがIO内に整数のリストを返します。

f :: Int -> IO [Int] 

ですが、IO of list of Integersに適用したいと思います.2つのコンテナ、つまりIOに含まれるリストにラップされているため、通常のバインド関数を使用することはできません。 Searching on hoogleは役に立ちません。私は私が欲しいものを得るために2つのヘルパー関数を使用しています

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で実装する方がより良い/慣用的な方法があるかどうかを知りたいのですが?

+0

私はすでにそれを持っているので、私は解決策を捜しているわけではありません。私はこれを解決するための慣用的な方法が欲しい。 – mandark

+0

あなたは答えをまだ読んだことがあるか分かりませんが、「より一般的には、どのタイプの関数がどのタイプの関数がm1 m2? - (m1 m2 b) - > m1 m2 b?重複した質問。答え:一般的なケースでは不可能です。 2番目の答えを見てください。 – 4castle

+1

'f''と' f'''の型シグネチャを取り除き、 'f'をパラメータに抽象化すると、型チェッカによって推論される最も一般的な型が得られます。これらの実装は、 '' = 'と' fmap'ではなく 'do'表記の使用を除いては、慣用的ですが、純粋に文体的な問題です。この質問は完全に意見に基づいています。コードが十分ではないこと、つまり「より良い」バージョンが達成したいと思っていることを明確にすることはできますか? – user2407038

答えて

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) 

は同様in this answerを説明し、 をfgMonadとするには十分ではありませんが、通勤する必要があります。

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 

(一般的には、it's not sufficient for f to be a monad and g to be Traversable

関連する問題