Зачем использовать нулевую функцию вместо == [] для проверки пустого списка в Haskell?
Я читаю главу "Начинаем" в " Learn You a Haskell for Great Good"! , Это говорит:
null
проверяет, является ли список пустым. Если это так, он возвращает True
, в противном случае он возвращает False
. Используйте эту функцию вместо xs == []
(если у вас есть список с именем xs
)
Я попробовал в ghci:
xs = [] -- and then,
xs == []
null xs
Они оба True
.
Интересно какая разница.
Должен ли я использовать null
функцию вместо == []
и почему?
Ответы
Ответ 1
Вы должны использовать null
. В большинстве случаев это не имеет значения, но это хорошая привычка, так как иногда вы можете захотеть проверить, пуст ли список несопоставимых вещей. Вот короткий, четкий пример, показывающий эту разницу:
> null [id]
False
> [id] == []
<interactive>:1:1: error:
• No instance for (Eq (a0 -> a0)) arising from a use of ‘==
(maybe you haven't applied a function to enough arguments?)
• In the expression: [id] == []
In an equation for ‘it: it = [id] == []
Ответ 2
Есть разница. Чтобы использовать x == []
, тип элементов списка должен быть членом класса типов Eq
. Действительно, проверка равенства двух списков определяется объявлением экземпляра:
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
Это означает, что вы не можете использовать x == []
если x
является, например, списком IO Int
s.
null :: [a] → Bool
с другой стороны, использует сопоставление с образцом. Это реализовано как:
null :: [a] -> Bool
null [] = True
null (_:_) = False
Таким образом, независимо от типа элементов списка, он всегда проверяет тип.
Ответ 3
В дополнение к хорошим ответам, данным до сих пор, null
самом деле имеет тип
null :: Foldable t => t a -> Bool
Я не знаю, добрались ли вы до классов типов в LYAH, но суть в том, что null
можно использовать не только для списков, но и для любой структуры данных, которая реализует null
.
Это означает, что использование null
на Map
или в Set
допустимо.
> null Map.empty
True
> null (Map.singleton 1)
False
> null Set.empty
True
> null (Set.singleton 1)
False
> null []
True
> null [1]
False
Я не думаю, что особенно часто пишут функции, которые должны быть такими общими, но по умолчанию не мешает писать более общий код.
Примечание стороны
Во многих случаях вы в конечном итоге захотите использовать такую функцию, как null
для выполнения условного поведения в списке (или другой структуре данных). Если вы уже знаете, что ваши входные данные представляют собой определенную структуру данных, более элегантно просто сопоставить шаблон с пустым регистром.
сравнить
myMap :: (a -> b) -> [a] -> [b]
myMap f xs
| null xs = []
myMap f (x:xs) = f x : myMap f xs
в
myMap' :: (a -> b) -> [a] -> [b]
myMap' f [] = []
myMap' f (x:xs) = f x : myMap' f xs
В общем, вы должны попытаться предпочесть сопоставление с образцом, если это имеет смысл.
Ответ 4
Также простая функция, которая фильтрует весь пустой список, не будет работать:
withoutEmpty = filter (== [])
и это будет:
withoutEmpty = filter null
заметить, что:
withoutEmpty ls = filter (==[]) ls
будет работать просто отлично, но важным моментом является то, что в некоторых случаях, как и в другом, может произойти сбой.
Также посмотрите на ответ @cole, он дополняет все ответы здесь, класс типов Foldable имеет реализованную здесь null
функцию:
Чтобы увидеть больше информации складной здесь