Проверка, является ли результат фильтра пустым списком

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

isListEmpty ::((a -> Bool) -> [a] -> [a]) -> Bool
isListEmpty f       | length f == 0 = True
                    | otherwise = False

Ошибка:

...- Type error in application
*** Expression     : length f
*** Term           : f
*** Type           : (b -> Bool) -> [b] -> [b]
*** Does not match : [a]

идея состоит в том, чтобы практиковать функции высшего порядка. Любая идея, как я могу это решить?


person Afflatus    schedule 27.01.2013    source источник
comment
Вы не применили функцию фильтра. Это ошибка.   -  person Gabriel Gonzalez    schedule 27.01.2013
comment
Я хотел использовать эту функцию как isListEmpty (filter (\(x,y,_,_,_)-> x == user && y == pass ) y). другими словами, функция фильтра является аргументом.   -  person Afflatus    schedule 27.01.2013


Ответы (4)


Похоже, у вас неправильные аннотации типа. Рассмотрим следующее решение:

isListEmpty :: (a -> Bool)        -- filtering function
            -> [a]                -- given list
            -> Bool               -- the result
isListEmpty f = null . filter f

Несколько примеров:

> isListEmpty odd [2, 4]
True
> isListEmpty odd [1, 2, 4]
False
> 

Использование length — не лучшая идея, так как для проверки приходится перебирать весь список, а список может быть даже бесконечным. null может справиться с этой задачей:

> isListEmpty even [1..]
False
> 

Изменить 1:

наш вопрос просил нас использовать встроенную функцию фильтра в качестве аргумента

Не совсем понимаю, что это значит, но вы можете сделать это:

isListEmpty :: ([a] -> [a]) -> [a] -> Bool
isListEmpty = (null .)

Пример использования:

> isListEmpty (filter even) [1..]
False

Пожалуйста, предоставьте мне пример предполагаемого вызова функции, если я ошибаюсь.

person nameless    schedule 27.01.2013
comment
эта функция действительно работает, но наш вопрос просил нас использовать встроенную функцию фильтра в качестве аргумента. здесь мы сделали фильтрацию сами. - person Afflatus; 27.01.2013
comment
Спасибо! это пример isListEmpty (filter (\(x,y,_,_,_)-> x == user && y == pass ) userList) - person Afflatus; 27.01.2013
comment
@Elham, ваш пример показывает, что тип вашей функции должен быть следующим: isListEmpty :: [a] -> Bool. На самом деле это функция null. Таким образом, вы можете просто определить isListEmpty следующим образом: isListEmpty = null :) - person nameless; 27.01.2013
comment
ты прав. Я написал то же самое в классе, но лектор попросил меня написать HOF. ›.‹ Я полагаю, он мог иметь в виду отделить от него функцию фильтрации, как это сделали вы. еще раз спасибо! - person Afflatus; 27.01.2013

isListEmpty ::((a -> Bool) -> [a] -> [a]) -> Bool
isListEmpty f       | length f == 0 = True
                    | otherwise = False

Первый параметр вашей функции isListEmpty — это функция, которой вы дали имя f и ее тип (a -> Bool) -> [a] -> [a]., и вы передаете f в length, это не работает, потому что функция length принимает типы с сигнатурой [a] и создает тип Int.

Вы можете увидеть это, зайдя в ghci и набрав :t length, что даст [a] -> Int.

Если вы сначала примените f к списку, который имеет тип [a], то вы можете использовать length и ==0, чтобы проверить, пуст ли он. Однако функция null является идиоматическим методом проверки того, пуст ли список или нет, поэтому я рекомендую использовать ее вместо этого.

Изменить добавить пример того, как написать аналогичную функцию.

Допустим, я хотел найти длину списка после выполнения другой функции, такой как drop, init и т. д. Сначала просто напишите функцию полностью со всеми аргументами:

manipulateList :: ([a] -> [a]) -> [a] -> Int
manipulateList fn lst = length (fn lst)

Вместо length (fn lst) мы можем переписать это с функциональной композицией (length.fn) lst

manipulateList :: ([a] -> [a]) -> [a] -> Int
manipulateList fn lst = (length.fn) lst

Теперь вы можете отменить lst с обеих сторон так же, как в алгебраическом уравнении.

manipulateList :: ([a] -> [a]) -> Int
manipulateList fn = (length.fn)

Теперь у нас есть функция более высокого порядка, которая принимает функцию fn и находит длину списка после применения к ней fn.

person Davorak    schedule 27.01.2013
comment
Я знаю, но это length (filter (>2) [2,1,9]) работает в Hugs. - person Afflatus; 27.01.2013
comment
После этого комментария у меня появилось лучшее представление о том, что вы пытаетесь сделать. С length (filter (>2) [2,1,9]) функция фильтра сначала применяется к списку, создавая другой список, длину которого вы затем определяете. С помощью length f вы применяете длину к функции. Я думаю, что понимаю, что вы пытаетесь написать, теперь я добавлю пример в свой ответ. - person Davorak; 27.01.2013
comment
Было бы здорово! Спасибо! - person Afflatus; 27.01.2013
comment
@Elham помогает ли этот пример прояснить, как бы вы написали функцию более высокого порядка? - person Davorak; 27.01.2013
comment
это первое, что я узнаю о композиции функций. Это круто. Я пробовал length.f, но эта композиция типа ([a] -> [a]) -> Int - person Afflatus; 27.01.2013
comment
@Elham прямо сейчас вы можете составить его с помощью функции тестирования, которая принимает Int и производит Bool, поэтому Int -> Bool. Если вы хотите проверить, равна ли длина нулю. - person Davorak; 27.01.2013
comment
давайте продолжим это обсуждение в чате - person Davorak; 27.01.2013

Во-первых: ошибка возникает из-за того, что вы обращаетесь с этой функцией так, как будто у вас есть только один вход — список. Ваша подпись типа, с другой стороны, запрашивает функцию от a до Bool и два lists of type a.

Во-вторых: Вы сказали, что вам нужно написать функцию, которая проверяет, пуст ли список, к которому применяется функция фильтра. Но вы только тестируете, если список пуст, никакое приложение вашей функции фильтра (вы (как я описал выше) даже ничего не делали с функцией.

Третье: один маленький совет: начните с

isListEmpty f xs | length xs == 0 = True
                 | otherwise      = ...  ||  isListEmpty f ...

вы должны что-то заполнить для ... . || означает логическое "ИЛИ", если вы этого не знаете.

person kaan    schedule 27.01.2013
comment
о, я видел твой комментарий к посту Даворака, знаю. Я думал, вам не разрешено использовать функцию filter. - person kaan; 27.01.2013

Вы можете просто сделать:

null $ (filter (>2) [2,1,0]) ==> True
null $ (filter (>2) [2,1,9]) ==> False

с :

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

Или с помощью HOF (как уже было сказано, это решение неверно, я не использую HOF)

hof_null filter 
    | (null $ filter) = True
    | otherwise       = False


not_null (filter (>2) [1,1,3]) ==> False
not_null (filter (>2) [1,1,1]) ==> True

....

Последняя попытка (спасибо Давораку)

hof_null fn = null.fn
person zurgl    schedule 27.01.2013
comment
null — это встроенная функция. идея заключалась в том, чтобы использовать функцию фильтра в качестве аргумента для другой функции более высокого порядка. - person Afflatus; 27.01.2013
comment
В вашем примере hof_null нет HOF. hof_null на самом деле просто псевдоним null. - person nameless; 27.01.2013
comment
Да, я тоже так думал, спасибо за подтверждение, я попробую что-нибудь еще - person zurgl; 27.01.2013