Haskell подсчитывает элементы списка - PullRequest
0 голосов
/ 09 декабря 2011

У меня есть этот код, который я пытался создать, чтобы подсчитать количество записей и распечатать их. Кажется, я не могу заставить его работать. Я постоянно получаю ошибки о том, что функция reportReg применяется к одному аргументу, но ее тип [String] не имеет ни одного.

report :: [[String]] -> String -> [String]
report (x:xs) typ = do
                    case typ of
                        "registrations" -> reportReg (map head xs)
                        "completions" -> reportReg (map head xs)

reportReg :: [String]
reportReg [x] = do
                    print x
                    print 1
reportReg (x:xs) = do 
                    let count = instances x (x:xs)
                    print x
                    print count
                    let newlist = filter (==x) (x:xs)
                    reportReg newlist

instances::String->[String]->Int
instances x [] = 0
instances x (y:ys)
    | x==y = 1+(instances x ys)
    | otherwise = instances x ys

Кроме того, есть ли более простой способ сделать это?

Ответы [ 3 ]

5 голосов
/ 09 декабря 2011

Проблема:

Вы дали reportReg тип списка строк:

reportReg :: [String]

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

Решения:

  • ПохожеВы хотите выполнить действия ввода-вывода в reportReg, поэтому вам следует изменить аннотацию типа:

    reportReg :: [String] -> IO ()
    

- или -

  • написать функцию без аннотации типа, пусть Haskell выведет ее для вас, а затем скопировать эту аннотацию

Проблема:

report Тип возврата неверный.Он должен быть таким же, как у reportReg.Но reportReg :: String -> IO (), тогда как report :: [[String]] -> String -> [String]!

Пара возможных решений:

  • удалить действия ввода-вывода из reportReg, чтобы его тип был [String] -> [String].Я настоятельно рекомендую сделать это - ввод-вывод на любом языке - это всегда боль, но в Haskell замечательно то, что он заставляет вас чувствовать боль - тем самым дает вам стимул избегать ввода-вывода в максимально возможной степени!
  • изменить тип report на [[String]] -> String -> IO ()

Решение для ленивого:

Я скопировал ваш код в текстовый файл,удалил аннотации (не внося никаких других изменений) и загрузил их в ghci:

Prelude> :load typef.hs 
[1 of 1] Compiling Main             ( typef.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t report
report :: (Eq a, Show a) => [[a]] -> [Char] -> IO ()
*Main> :t reportReg 
reportReg :: (Eq a, Show a) => [a] -> IO ()
*Main> :t instances 
instances :: (Num t, Eq a) => a -> [a] -> t

Работает - Haskell выводит типы! Но он может не делать то, что вы хотите.

4 голосов
/ 09 декабря 2011

Мне кажется, я вижу, что происходит.

reportReg :: [String]

объявляет, что reportReg является списком строк. Но вы хотите, чтобы reportReg была функцией (помечена в типе ->), которая принимает список строк:

reportReg :: [String] -> ???

Теперь единственный вопрос - что идет вместо ??? - что возвращает reportReg?

Именно здесь Хаскель отличается от всех остальных языков. Возвращает I / O action . Это функция, которая отображает списки строк в действия, а именно, что-то в do , а не в возвращаемое значение (поэтому оно возвращает значение - но цель этого значения - описать, что делать). Пишем тип таких описывающих действие значений IO (). Итак:

reportReg :: [String] -> IO ()
0 голосов
/ 13 декабря 2011

Другие люди указали причину вашей ошибки, но я прокомментирую другую проблему, которую вы подняли:

Кроме того, есть ли более простой способ сделать это?

Да, простой способ подсчета элементов списка - использовать функцию length.Если вам нужно посчитать, сколько элементов удовлетворяют предикату, вы можете взять длину результата фильтрации.Я не совсем понимаю ваш код (например, что делает этот аргумент typ?), Но вот пример (который, вероятно, не делает то же самое):

reportReg :: [a] -> IO ()
reportReg [] = do return ()
reportReg xs = do print (head x)
                  print (count x xs)
                  reportReg (tail xs)

count :: a -> [a] -> Integer
count x xs = length (filter (==x) xs)

Основная частьСовет Я бы посоветовал извлечь как можно больше кода из блоков do (мой код, приведенный выше, все еще может использовать улучшения в этом отношении).Постарайтесь полностью решить вашу проблему с точки зрения чистого кода и используйте монаду ввода-вывода только для вывода результата.

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