1

I am trying to write a function that takes in a predicate and a list and returns a list that satisfies the predicate.

So, for instance, I want something like this:

haskell> count_if (x > 3) [2,3,4,5,6] 
[4,5,6]

Here's what I have so far:

count_if f [] = 0 
count_if f (x:xs) 
  | f x = x : count_if f xs
  | otherwise = count_if f xs 

My question is, how do I test this function using a predicate?

4

4 に答える 4

4

filterこの目的のための機能があります。とにかく、count_ifまたはフィルターをテストするには、次のようなことを行うことができます

filter (>3) [2,3,4,5,6]
于 2012-12-15T18:59:09.670 に答える
3

リスト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] -> Intxで前面に置く代わりに、で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_iffilterfilter :: (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が、それは別の日のレッスンです!)

のような標準機能を使用するfilterlength、自分では見つけられない可能性のあるパフォーマンスの向上につながる可能性があります。countif (>0) [1..1000000]に対してテストするとcount_if (>0) [1..1000000]、実行速度が著しく速くなります。このため、プレリュードから、、などfilterのプレリュード関数を理解することをお勧めします。foldrscanr

于 2012-12-18T17:15:29.380 に答える
2

述語を書く方法はいくつかあります。述語であるいくつかの組み込み関数があります。次に例を示します。

even :: Integer -> Bool
odd  :: Integer -> Bool
null :: [a] -> Bool

比較演算子で演算子セクションを使用できます。

(== 0) :: Integer -> Bool
(3 >)  :: Integer -> Bool

または、ラムダ式を使用して、より複雑な述語を記述できます。

(\x -> 1 < x && x < 5) :: Integer -> Bool

したがって、たとえば、次のようにする必要があります。

count_if even [1,2,3,4,5,6]                   -->  [2,4,6]
count_if (3 >) [1,2,3,4,5,6]                  -->  [1,2]
count_if (\x -> 1 < x && x < 5) [1,2,3,4,5,6] -->  [2,3,4]
于 2012-12-15T23:12:57.913 に答える
1

フィルタと呼ばれるそのための既存の関数があります

参照:http ://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:filter

編集:

したがって、問題は、実装がほぼ正しいことです。

count_if f [] = 0 

する必要があります

count_if :: (a -> Bool) -> [a] -> [a]
count_if f [] = []
count_if f (x:xs) 
| f x = x:count_if f xs
| otherwise = count_if f xs 

関数のタイプを指定すると、コンパイラが役立ちます

于 2012-12-15T18:59:08.440 に答える