Foldl1が(==)演算子を適用しなかったのはなぜですか?
-
29-10-2019 - |
質問
から プレリュード:
foldl1: :リストの最初の2つの項目を取り、関数を適用し、この結果と3番目の引数などで関数をフィードします。
なぜこのようなものを書くことができないのですか?
foldl1 (==) [6, 6, 6]
foldl1 (\x y -> x == y) [6, 6, 6]
解決
編集:Antalは、私の推論が間違っていたことを指摘しています。これは、本当の推論を与えるコメントの関連部分を示します(この逐語的に服用するのは気分が悪いですが、この答えは受け入れられたので、削除できません):
これがうまくいかない理由は、 foldl1
は (a -> a -> a) -> [a] -> a
, 、しかしのタイプ (==)
は Num a => a -> a -> Bool
. 。以来 Bool
ではありません Num
, (==)
タイプは一致しません a -> a -> a
, 、したがって、の適用 foldl1
拒否されます。それが受け入れられた場合、あなたはあなたがやろうとしている状況になります True == 6
, 、しかし、タイプシステムがそもそもそれを獲得することはありません。
元の答え(後者の推論が間違っている):
==
2つかかります Int
sと返品a Bool
. 。最初のイテレーションの後、あなたのサンプルリストはなります [True, 6]
. 。その後、比較しようとします True
に 6
失敗します。
他のヒント
リストのすべての要素が等しいかどうかを確認する場合、迅速な解決策は
allEqual [] = True --(edit: this case is not necessary as pointed out by sepp2k)
allEqual xs = all (== head xs) xs
誰かがこれを行うためのよりエレガントな方法を書くでしょう、と私は確信していますが、これはサービス可能です。
編集:提案をしてくれたSEPP2Kに感謝します。
これが別のバージョンです:
allEqual xs = and $ zipWith (==) xs (tail xs)
折り目を使用したい場合は、この変更をお勧めします。
allEqual xs = foldr (\x acc -> x == head xs && acc) True xs
これは、すでに接続されているものと非常に似ています all
アプローチ。これと両方の両方に注意してください all
アプローチは無限のリストで動作することができます(答えがある限り False
).
非常に長い有限リストの場合、非常にまれな場合には、厳格な左折り目からより良いパフォーマンスが得られる可能性があります。
allEqual xs = foldl' (\acc x -> acc && x == head xs) True xs
しかし、(この実装では)等しい折り畳みステップのみを実行するため、この問題に対しては正しい倍数が一般的に優れています。 length $ takeWhile (== head xs) xs
. 。左折が実行されます length xs
毎回折りたたみステップ。