リストcountif
を作成するように指示したため、関数は何かを数えるのに苦労しています。
count_if f [] = 0 -- fine, makes sense
count_if f (x:xs)
| f x = x : count_if f xs -- Oops, no!
| otherwise = count_if f xs -- yup
1:[2,3]
=[1,2,3]
であることに注意してください。これ:
は、リストの先頭に追加の要素を配置するためのものです。数えたい場合は、リストではなく数字が必要です。(前面に置くx
と、のようfilter
に聞こえます。これにより、述語が真であるすべての要素が得られますが、カウントしたかったのですが、これは異なります。)
のような明示的な型シグネチャを与えることで、期待していたことをコンパイラに伝えると、このタイプのエラーをより簡単に見つけることができますcount_if :: (a -> Bool) -> [a] -> Int
。x
で前面に置く代わりに、でx:
1つ追加して1+
、
count_if :: (a -> Bool) -> [a] -> Int
count_if f [] = 0
count_if f (x:xs)
| f x = 1 + count_if f xs -- adds one to the total from the rest
| otherwise = count_if f xs
これで、次のようにテストできます。
> count_if (>5) [1..10]
5
> count_if (=='e') "Time is of the essence"
5
> count_if even [1..100]
50
これで、を使用して作成できます。フィルタの種類はであり、必要な要素だけを提供します。count_if
filter
filter :: (a -> Bool) -> [a] -> [a]
> filter (>5) [1..10]
[6,7,8,9,10]
> filter (=='e') "Time is of the essence"
"eeeee"
しかし、結果に長さを加えます。
countif' :: (a -> Bool) -> [a] -> Int
countif' f xs = length (filter f xs)
しかし、それは少しきちんと書くことができます
countif :: (a -> Bool) -> [a] -> Int
countif f = length . filter f
.
は関数の合成であるため、これはでフィルターを実行しf
、長さを取ります。
(ポイントフリーオタクはこれを次のように書くことを好みますcountif = (length.).filter
が、それは別の日のレッスンです!)
のような標準機能を使用するfilter
とlength
、自分では見つけられない可能性のあるパフォーマンスの向上につながる可能性があります。countif (>0) [1..1000000]
に対してテストするとcount_if (>0) [1..1000000]
、実行速度が著しく速くなります。このため、プレリュードから、、などfilter
のプレリュード関数を理解することをお勧めします。foldr
scanr