2016-04-07 30 views
2

は、私は、リストはHaskellのガードに二つの選択肢がある空であるかどうかを確認したいと?私は、プレリュード関数ではなくより基本的な構文に頼っているので、空リストテストを言う傾向がありますが、私は確信していません。ハスケルの空リストをチェックする:(長さリスト== 0)または(リスト== [])がより効率的ですか?より効率的にこれらの二つの論理テストの</p> <ol> <li><code>length list == 0</code></li> <li><code>list == []</code></li> </ol> <p>:

+9

1はリストの長さが線形(明らかに)で、2は一定時間です。しかし、2は本当に必要でないときに 'Eq'制約が必要なという落とし穴があります。ヌルの空リストをチェックするか、単純にパターンマッチングでチェックしてください。 – user2407038

+0

他の定義済みのリストと同等かどうかを比較したいときは、パターンマッチングは機能しません –

+0

また感謝します。あなたはヌルについて詳しく説明できますか? –

答えて

6

length list == 0は、長さを得るためにリスト全体を走査する必要があります。つまり、O(n)です。 list == []は、要素タイプにEqという制約をもたらします。 null listは一定の時間で実行され、typeclassの制約はありません。

しかし、それは長いリストを経由せずlength list1 == length list2にうまく一般化という利点がありlength list == 0ような何かをするために巧妙なトリックがある:比較のみをするように、あなたは自然数の十分怠惰な表現とgenericLengthを使用することができますリストのうち短いほうを横切るような力。

一例はthe Natural typeを使用することです:

import Data.Number.Natural 
import Data.List (genericLength) 

nats :: [Int] 
nats = iterate succ 0 

areThereTenNats :: Bool 
areThereTenNats = genericLength nats >= (10 :: Natural) 
+1

「自然数の十分に怠惰な表現」は、非効率的で、ばかげて非効率的であることの間で変化します。また、OPの問題に対する他の解決策は、少なくとも「ヌル」と同じことをしなければならないことです。 –

+2

@DerekElkins、第1引数でのパターンマッチングによる追加と、第2引数での「パラメトリック」による従来の実装は、うまく動作します。それでも、 'genericLength'ソースコードと' + '実装ソースコードを読む必要があります。パラメトリックを使って 'forall a。 'を見るのはもっと明らかです。 [a] 'は自然数である。 – dfeuer

+2

@dfeuer "== 0"の場合はもっと明確にすべきだったと思いますが、 "null"より速くないのは過度に非効率的ではありません。それ以外の場合は、2つのポインタを並行して割り振りを必要とせずに無駄な計算をするためのレシピです。それはポインタの歩行と同じ漸近効率を持っています。あなたが効率を心配している場合、「怠惰な自然」型に切り替えることは、あなたがやるべきこととまったく逆のことであることを示したかっただけです。 (私はCactusがそう言っていると言っているわけではありません) –

3

他の人が示されているとおり、リストが空(およびより何)であるかどうかを確認するための最良の方法はどのできる

null :: Foldable f => f a -> Bool 

を使用することですタイプで使用する

null :: [a] -> Bool 

あなたが弱いのでリストが空であるかどうかチェックしたい場合

f [] = something 
f (x : xs) = something using x and/or xs 

あなたは二つのリスト(およびこれ以上)の長さを比較したい場合は、最良の方法は、通常

のようなものである:そう、あなたは一般的に代わりにパターンマッチングを使用する必要があり、その要素を見てトン
compareLength :: [a] -> [b] -> Ordering 
compareLength [] [] = EQ 
compareLength [] (_ : _) = LT 
compareLength (_ : _) [] = GT 
compareLength (_ : xs) (_ : ys) = 
    compareLength xs ys 

リストの長さが一定数と比較する方法をチェックするための最良の方法は、あなたのリストが空の場合は、に一定の時間で確認することができます

compareToLength :: Foldable f 
       => f a -> Int -> Ordering 
compareToLength = foldr go (compare 0) where 
    go _ r n | n <= 0 = GT 
      | otherwise = r $! n - 1 
+1

'' compareLength = compare 'on'(()<$)' 'は、もっと簡潔にするために長さを比較するもう一つのオプションです。 – semicolon

+0

@セミコロン、良い点。あなたはそれを答えることさえできます。 'compare(replicate n())(()<$ xs)'も同様に便利です。これらのどちらも手で行うほど効率的ではありませんが、どちらも恐ろしいことはありません。 – dfeuer

+0

@WillNess、これはGHCiのものでしたか?私は最適化されたコードについて話しています。 – dfeuer

0

ですはブール値を返します。

+0

はい、この回答は[dfeuer's](https://stackoverflow.com/a/36481943/745903)に何を追加していますか? – leftaroundabout

関連する問題