10

関数を実装しようとしていました

every :: (a -> IO Bool) -> [a] -> IO Bool 

これがこの質問のトピックでした。明示的な再帰なしでこれを実行しようとしました。私は次のコードを思いついた

every f xs = liftM (all id) $ sequence $ map f xs

私の関数は怠惰ではなかったので機能しませんでした(これは質問で必要でした)ので、そこには賛成票はありません:-)。

しかし、私はそこで止まりませんでした。関数をポイントフリーにして、短くする(そしておそらくもっと涼しくする)ようにしました。引数fxsは式の最後のものなので、私はそれらを削除しました:

every = liftM (all id) $ sequence $ map 

しかし、これは期待どおりに機能しませんでした。実際、まったく機能しませんでした。

    [1/1]メインのコンパイル(stk.hs、インタプリタ)

    stk.hs:53:42:
        期待されるタイプ`[ma]'と一致しませんでした
               推論された型に対して`(a1-> b)-> [a1]-> [b] '
        `($)'の2番目の引数、つまり` map '
        `($)'の2番目の引数、つまり` sequence $ map '
        式:liftM(すべてのID)$シーケンス$マップ
    失敗、モジュールのロード:なし。

何故ですか?基本的にカリー化の目的である、末尾の関数の引数を単純に削除できるという印象を受けました。

4

1 に答える 1

25

$の定義は

f $ x = f x

関数を完全に括弧で囲んでみましょう。

every f xs = (liftM (all id)) (sequence ((map f) xs))

とあなたのカレーバージョン:

every = (liftM (all id)) (sequence map)

お気づきのように、これらは同一ではありません。末尾の関数の引数は、最後に適用される場合にのみ削除できます。例えば、

f x = g c x

実は

f x = (g c) x

xへの(gc)の適用が最後になるので、次のように書くことができます。

f = g c

アプリケーション演算子$のパターンの1つは、それが合成演算子になることが多いということです。ポイントフリーバージョンで。それの訳は

f $ g $ x

と同等です

(f . g) $ x

例えば、

every f xs = liftM (all id) $ sequence $ map f xs

になることができる

every f xs = (liftM (all id) . sequence . map f) xs

その時点でxsをドロップできます:

every f = liftM (all id) . sequence . map f

引数fは、合成演算子の前に適用されるため、削除するのはより困難です。http://www.haskell.org/haskellwiki/Pointfreeのドットの定義を使用してみましょう:

dot = ((.) . (.))

ポイントで、これは

(f `dot` g) x = f . g x

そして、まさにそれが私たちがすべてを完全にポイントフリーにするために必要なものです:

every = (liftM (all id) . sequence) `dot` map

悲しいことに、Haskell型システムの制限により、これには明示的な型シグネチャが必要です。

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
于 2009-05-25T17:15:49.277 に答える