web-dev-qa-db-ja.com

Haskellで空のリストを確認する:(長さリスト== 0)または(リスト== [])の方が効率的ですか?

Haskellのガードでリストが空かどうかを確認したい場合、2つのオプションがあります。

  1. length list == 0
  2. list == []

これらの2つの論理テストのどちらがより効率的ですか?プレリュード関数lengthではなく、より基本的な構成に依存しているため、私は空のリストテストを言う傾向がありますが、よくわかりません。

14
J-S

length list == 0は、リスト全体を走査してその長さを取得する必要があります。つまり、O(n)です。 list == []は、エレメントタイプにEq制約を生成します。 null listは一定の時間で実行され、型クラスの制約はありません。

ただし、length list == 0のようなことをするための巧妙なトリックがあり、長いリストを経由せずにlength list1 == length list2にうまく一般化できるという利点があります。 genericLengthを使用できます。 自然数の十分に遅延した表現を使用して、比較がリストの短い方のみをトラバースするようにします。

1つの例は the Natural type を使用することです:

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

nats :: [Int]
nats = iterate succ 0

areThereTenNats :: Bool
areThereTenNats = genericLength nats >= (10 :: Natural)
16
Cactus

他の人が示したように、リストが空であるかどうか(そしてそれ以上何もないか)を確認する最良の方法は、

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

タイプで使用できる

null :: [a] -> Bool

リストの要素を確認するためにリストが空かどうかを確認する場合は、通常、代わりにパターンマッチングを使用する必要があります。

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

2つのリストの長さを比較したい場合(それ以上)は、通常、次のような方法が最適です。

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
9
dfeuer

ブール値を返すnull listを使用して、リストが一定時間空であるかどうかを確認できます。

Prelude> null []
True
Prelude> null [1]
False
Prelude> null ""
True
Prelude> null "Test"
False
7
manonthemat