5

関数パラメーターから取得した値を使用して計算を実行する高次関数があるとします。

f :: a -> (b -> c) -> d

ここで、a、b、c、d は具体的な型です。

次に、このタイプの関数があります

g :: b -> m c

ここで、m は何らかのモナドです。

f で g を使用する方法があります。つまり、f をm d代わりに生成し、 d2 番目のパラメーターとして g を使用できる関数に変換しますか?

具体的な例としては、m が IO モナドで、f が関数パラメータから取得した n 個の数値の合計を計算する関数であり、g が標準入力から数値を読み取る場合です。

f n g = sum $ map g (1..n)
g :: Int -> IO Int
g _ = readLn

標準入力を遅延リストに変換する関数があることは知っていますが、これでこの問題は解決しますが、私の実際の状況はそれほど単純ではありません。

グラフで何かを行うためのアルゴリズムがあるとします。このアルゴリズムは、関数パラメータを使用してノードの隣接ノードを決定します。これは、グラフを複数実装できるようにするためです。

今、私はこのアルゴリズムを非決定論的グラフ (リストモナド) または完全に知られていないグラフ (おそらくモナド) で使用したいと考えています。モナドを使用するようにアルゴリズムを書き直してから、基本的なケースで恒等モナドを使用できることは知っていますが、これが唯一の方法ですか? モナドなしでアルゴリズムを書く方が簡単だと思います。

この動作は可能ですか? そうすべきではない理由を見つけることができませんでしたが、それを行う方法を見つけることができませんでした。

4

1 に答える 1

7

mapMしたがって、たとえば、 givenを派生させたいとしますmap。つまり、あなたは単純mapです:

map  :: (a -> b) -> [a] -> [b]

そして、それをモナド構造で使用したいmap

mapM :: Monad m => (a -> m b) -> [a] -> m [b]

mapMIO アクションをマッピングしmap、それらを順序付けすることで、次のように計算できます。

mapM f xs = sequence (map f xs)

これで、より一般的な形式になり、Identity モナドmapを実行mapMして元に戻すことができます。そしてクラシックは単位モナドにあります。mapmapM

> let g :: Int -> Identity Int
      g a = return (a^2)

どこ:

> runIdentity $ mapM g [1..10]
[1,4,9,16,25,36,49,64,81,100]

そうです、高階関数を適切なレベルに一般化する必要があります-そのモナド、ファンクター、またはアプリカティブであっても、アイデンティティを含む計算の他の概念に自由に置き換えることができます。

関数の AST を変換することにより、任意の純粋な関数をそのモナドに機械的に書き換えることができます。

  • 結果値をラップするreturn
  • 新しいモナド部分式を識別し、それらをバインドします。
  • 変数バインディングをモナド バインドに置き換えます。または、適用可能な場合:
  • アプリケーションをモナド内のアプリケーションに置き換える (注意してください)

例えば

map f []     = []
map f (x:xs) = f x : map f xs

To (応用的なスタイル)

mapM f []     = return []
mapM f (x:xs) = (:) <$> f x <*> mapM' f xs

またはあまり明確ではなく、評価順序を修正します。

mapM f []     = return []
mapM f (x:xs) = do
    v  <- f x
    vs <- mapM f xs
    return (v:vs)

あるステップから次のステップに結果を伝えるためにモナド バインドが必要ないため、マップにアプリケーションを使用できます。の場合はそうではありませんfoldl:

foldl        :: (a -> b -> a) -> a -> [b] -> a
foldl f z0 xs0 = lgo z0 xs0
     where
        lgo z []     =  z
        lgo z (x:xs) = lgo (f z x) xs

foldlM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a
foldlM f z0 xs0 = lgo z0 xs0
     where
        lgo z []     = return z
        lgo z (x:xs) = do
            v <- f z x
            lgo v xs
于 2013-03-03T12:46:17.907 に答える