Haskellのガードでリストが空かどうかを確認したい場合、2つのオプションがあります。
length list == 0
list == []
これらの2つの論理テストのどちらがより効率的ですか?プレリュード関数length
ではなく、より基本的な構成に依存しているため、私は空のリストテストを言う傾向がありますが、よくわかりません。
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)
他の人が示したように、リストが空であるかどうか(そしてそれ以上何もないか)を確認する最良の方法は、
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
ブール値を返すnull list
を使用して、リストが一定時間空であるかどうかを確認できます。
Prelude> null []
True
Prelude> null [1]
False
Prelude> null ""
True
Prelude> null "Test"
False