Зачем использовать нулевую функцию вместо == [] для проверки пустого списка в Haskell?


person 徐保钰    schedule 14.07.2019    source источник


Ответы (4)


Вы должны использовать 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] == []
person Daniel Wagner    schedule 14.07.2019
comment
«В большинстве случаев это не имеет значения» – не соглашусь. Очень часто пишут полиморфные списочные функции, которые не должны требовать ограничения Eq (даже если в большинстве случаев они действительно создаются с Eq типами). - person leftaroundabout; 14.07.2019
comment
Я согласен со всем, что написано в этом ответе. Ради потомства и полноты, возможно, стоит упомянуть, почему length xs == 0 — плохая идея. - person Silvio Mayolo; 15.07.2019
comment
Для справки: length xs == 0 — плохая идея, потому что нужно пройти весь связанный список (который равен O(n) и никогда не заканчивается бесконечным списком). - person mb21; 16.07.2019

Есть разница. Чтобы использовать x == [], тип элементов списка должен быть членом Eq класс типов. Действительно, проверка равенства двух списков определяется объявлением экземпляра:

instance Eq a => Eq [a] where
    []     == []      =  True
    (x:xs) == (y:ys)  =  x == y  &&  xs == ys
    _      == _       =  False

Это означает, что вы не можете использовать x == [], если x, например, представляет собой список IO Int.

null :: [a] -> Bool< /a>, с другой стороны, использует сопоставление с образцом. Это реализовано как:

null                    :: [a] -> Bool
null []                 =  True
null (_:_)              =  False

Таким образом, независимо от того, какого типа элементы списка, он всегда будет проверять тип.

person Willem Van Onsem    schedule 14.07.2019

В дополнение к хорошим ответам, данным до сих пор, null на самом деле имеет тип

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

Я не знаю, добирались ли вы до классов типов в LYAH, но суть в том, что null можно использовать не только для списков, но и для любой структуры данных, реализующей null.

Это означает, что использование null в Map< /a> или 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

to

myMap' :: (a -> b) -> [a] -> [b]
myMap' f [] = []
myMap' f (x:xs) = f x : myMap' f xs

В общем, вы должны попытаться отдать предпочтение сопоставлению с образцом, если это имеет смысл.

person cole    schedule 14.07.2019

Также простая функция, которая фильтрует весь пустой список, не сработает:

withoutEmpty = filter (== [])

и это будет:

withoutEmpty = filter null

Заметь:

withoutEmpty ls = filter (==[]) ls

будет работать нормально, но важно то, что в некоторых случаях, как и в другом, может произойти сбой.

Также посмотрите на ответ @cole, он дополняет все ответы здесь, в классе типов Foldable есть функция null, которую нужно реализовать:

Чтобы увидеть больше информации о Foldable здесь

person Damián Rafael Lattenero    schedule 14.07.2019
comment
Этот ответ немного вводит в заблуждение. withoutEmpty = filter (==[]) может вызвать ошибку, но withoutEmpty x = filter (==[]) x работает нормально. - person Daniel Wagner; 15.07.2019
comment
@DanielWagner (или Дамиан) мог бы кто-нибудь из вас объяснить, почему только бесточечная версия не может проверить тип? - person Leif Willerts; 16.07.2019
comment
@LeifWillerts Что такое ограничение мономорфизма? - person Daniel Wagner; 16.07.2019