Позвольте мне сначала переписать вашу функцию немного, так как
isListOk :: Bool
isListOk = length (filter isItemOk [1 .. 1000]) <= 3
, возможно, более идиоматических, чем версии. (Обратите внимание, что я также изменил тип подписи, как у вас было неправильно. Кроме того, вы должны быть написаны 1 .. 1000
, а не 1.1000
.)
Ленивые вычисления ваш лучший друг здесь, как правило убедитесь, что никаких ненужных вычислений не будет выполнено.
К сожалению, использование вами length
(или отображение каждого элемента из списка в 1, а затем суммирование итогового списка, как вы это делаете) находится здесь. То есть length
является строгим в списке позвоночника: он может производить только длину списка, если он оценивает его до самого конца, что в данном случае означает, что ваша программа должна будет выполнить вашу проверку тысячу раз ,
Решение состоит в объединении вычисления длины (т.е., Обход позвоночника списка) и тест ли вычисленная длина не превышает заданный порог в одну функцию, которая на самом деле ленивым в позвоночнике своего списка аргументов:
isNotLongerThan :: [a] -> Integer -> Bool
isNotLongerThan [] n = n >= 0
isNotLongerThan (_ : xs) n = n >= 1 && isNotLongerThan xs (n - 1)
, а затем записать
isListOk :: Bool
isListOk = filter isItemOk [1 .. 1000] `isNotLongerThan` 3
Для многоразового решения, вы можете, конечно, абстрактный над как предиката и порога:
forNoMoreThan :: (a -> Bool) -> Integer -> [a] -> Bool
forNoMoreThan p n = (`isNotLongerThan` n) . filter p
isListOk :: Bool
isListOk = (isItemOk `forNoMoreThan` 3) [1 .. 1000]
Наконец, как Хаммар указывает, если молотить старый достаточно мал и исправлен, вы можете просто использовать сопоставление образцов, чтобы определить, достаточно ли список.
Ваша функция не будет выглядеть выше 4, поскольку 'take' и' list comprehension' являются ленивыми. Попробуйте использовать 'Int', если вы знаете, что ваш номер не будет превышать лимит, поскольку он намного быстрее, чем' Integer'. Это 'Bool', а не' Boolean'. 'isListOk' должен принимать аргумент списка. – Satvik