2013-12-08 10 views
0

Я пытаюсь создать функцию countElems, которая принимает Int и [Int] и возвращает, сколько из этого конкретного Int находится в списке. До сих пор у меня есть:В Haskell, как подсчитать количество конкретных Int в списке

countElems :: Int -> [Int] -> Int 
countElems n (x:xs) 
| xs == [] = 0 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

При запуске, это похоже на работу, но при дальнейшем осмотре, если вы вводите countElems 9 [5, 3, 9, 3, 9] выход 1 вместо 2. Я вижу это потому, что он проверяет, что xs == [], прежде чем увидеть, если n == x приводит к некорректному выходу, но если я поменяю эти два случая вокруг, то говорит Non-exhaustive pattern.

Редактировать после дальнейших размышлений:

Я мог бы устранить ошибку @ user2407038 отправил с этим кодом:

countElems :: Int -> [Int] -> Int 
countElems _ [] = 0 
countElems n (x:xs) 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

Это выглядит менее элегантно, но работает точно так же?

ответ

2

Ваша функция не является исчерпывающим независимо от заказа вы поместите охранников Рассмотрим countElems 9 [].. Это ошибка, поскольку шаблон не совпадает с пустым списком. (Возможно, это желаемое поведение для вашего дела, но обычно ошибки являются плохими). Рассмотрите возможность использования сопоставления с образцом здесь:

countElems n (x:xs) = fromEnum (n == x) + countElems n xs 
countElems _ []  = 0 

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

Здесь, вероятно, нет необходимости использовать явную рекурсию. Попробуйте \x = length . filter (==x).

+0

Мне нравится этот ответ, поскольку он делает мой лектор ошибочным, он сказал, что нам нужны два рекурсивных случая, но это очень аккуратный способ решить эту проблему, спасибо! – benharris

+5

@ benharris Лекторы очень часто «ошибаются» в том смысле, что то, чему они вас учат, не обязательно то, что написал бы опытный программист. В коде реального мира Haskell совсем нет рекурсии. Большинство из них могут быть реализованы с помощью библиотечных функций, что делает код более читаемым, более простым в обслуживании, менее подверженным ошибкам и так далее. – kqr

2

В вашей первой проверки (xs == [] = 0) вы забыли проверить x==n, в этом случае результат должен быть 1 вместо 0:

countElems n (x:xs) 
| xs == [] = if x==n then 1 else 0 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

Другой (возможно, более простой) реализация может посмотреть на список как целом:

cE n [] = 0 
cE n (x:xs) = (if n==x then 1 else 0) + (cE n xs) 
+0

Спасибо, первое решение является большим. Мне очень интересно узнать, что делает второе решение, хотя я не думаю, что я на этом уровне в Haskell, что же делает 'cE'? – benharris

+0

@benharris Название 'cE' просто намерено быть короткой формой для' countElems'. Он всегда «смотрит» на первый элемент и добавляет только один, если первый элемент - тот, который вы ищете. – phimuemue

0

Вы также можете написать его с помощью карты:

countElems :: Int -> [Int] -> Int 
countElems n xs = sum $ map (fromEnum . (==n)) xs 
5

Еще одно без рекурсивных положений:

countElem e = length . filter (e ==) 
Смежные вопросы