#haskell
Вопрос:
У меня есть такой ввод : статистика [(0,1),(1,3),(1,2)] где я хочу рассчитать некоторую информацию. Хорошо с этим, но когда я использую рекурсию для создания цикла, она отправляет мне ошибку, которую я не знаю, почему . Все,что я хочу, — это (в начале) принимать значения (x, y) и (в конце) сохранять другой список таким, какой он есть . Мой код :
statistics :: [(Int,Int)]->(Int,Int,Int,Int,Int)
statistics [] = (0,0,0,0,0)
statistics s = help_statistics s (head s) (tail s) 0 0 0 0 0 0
help_statistics :: [(Int,Int)]->(Int,Int)->[(Int,Int)]->Int->Int->Int->Int->Int->Int->(Int,Int,Int,Int,Int)
help_statistics s (x,y) taill counter matches total_points goal_for goal_against dif
|counter==0 = help_statistics s (head taill) (tail taill) (counter 1) length(s) total_points goal_for goal_against dif
|otherwise = (matches,total_points,goal_for,goal_against,dif)
ERROR file:.LAB3.hs:11 - Type error in application
*** Expression : help_statistics s (head taill) (tail taill) (counter 1) length s total_points goal_for goal_against dif
*** Term : help_statistics
*** Type : [(Int,Int)] -> (Int,Int) -> [(Int,Int)] -> Int -> Int -> Int -> Int -> Int -> Int -> (Int,Int,Int,Int,Int)
*** Does not match : a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
Комментарии:
1.
(length s)
вместоlength(s)
.2. @WillemVanOnsem ты потрясающий 😛 спасибо тебе !
3. Вероятно, вы захотите записать большинство этих аргументов в записи, чтобы их было легче читать. Кроме того, шаблон «go» — это хороший трюк, поэтому вам не нужно повторять все аргументы, которые не меняются при рекурсивном вызове
4. @WillemVanOnsem Могу я спросить еще кое о чем ? если я задам в качестве входных данных это [(1,5),(3,5)] , у меня был сбой соответствия шаблону : head [] как я могу это решить ?
5. Ах, да. Вы должны стараться избегать использования функций
head
иtail
как можно больше. Вместо этого используйте сопоставление с шаблоном, напримерf (x:xs) = something; f [] = something else
илиf xs = case xs of (x:xs) -> something; [] -> something else
(замените точку с запятой на новую строку, если хотите)
Ответ №1:
Позвольте мне просмотреть код и помочь вам с проблемами и сделать его более идиоматичным.
Давайте начнем с устранения проблемы length(s)
-> > (length s)
и уменьшения отступа, чтобы он лучше вписывался в экран.
statistics :: [(Int,Int)]->(Int,Int,Int,Int,Int)
statistics [] = (0,0,0,0,0)
statistics s = help_statistics s (head s) (tail s) 0 0 0 0 0 0
help_statistics :: [(Int,Int)]->(Int,Int)->[(Int,Int)]->Int->Int->Int->Int->Int->Int->(Int,Int,Int,Int,Int)
help_statistics s (x,y) taill counter matches total_points goal_for goal_against dif
|counter==0 = help_statistics s (head taill) (tail taill) (counter 1) (length s) total_points goal_for goal_against dif
|otherwise = (matches,total_points,goal_for,goal_against,dif)
Далее мы можем заменить head
и tail
на соответствие шаблону:
statistics :: [(Int,Int)]->(Int,Int,Int,Int,Int)
statistics [] = (0,0,0,0,0)
statistics s@(x:xs) = help_statistics s x xs 0 0 0 0 0 0
help_statistics :: [(Int,Int)]->(Int,Int)->[(Int,Int)]->Int->Int->Int->Int->Int->Int->(Int,Int,Int,Int,Int)
help_statistics s (x,y) (hd:tl) counter matches total_points goal_for goal_against dif
|counter==0 = help_statistics s hd tl (counter 1) (length s) total_points goal_for goal_against dif
|otherwise = (matches,total_points,goal_for,goal_against,dif)
help_statistics s (x,y) [] counter matches total_points goal_for goal_against dif
= _ -- What should we do with an empty list?
Следующий шаг-ввести новый тип данных, чтобы нам не приходилось работать с миллионами аргументов и каждый раз подсчитывать, какой аргумент нам нужен:
data Statistics = MkStatistics
{ matches :: Int
, total_points :: Int
, goal_for :: Int
, goal_against :: Int
, dif :: Int
} deriving Show
emptyStatistics :: Statistics
emptyStatistics = MkStatistics 0 0 0 0 0
statistics :: [(Int,Int)] -> Statistics
statistics [] = emptyStatistics
statistics s@(x:xs) = help_statistics s x xs 0 emptyStatistics
help_statistics :: [(Int,Int)]->(Int,Int)->[(Int,Int)]->Int-> Statistics -> Statistics
help_statistics s (x,y) (hd:tl) counter stats
|counter==0 = let stats' = stats {matches = length s} -- Update `matches` to a new value
in help_statistics s hd tl (counter 1) stats'
|otherwise = stats
help_statistics s (x,y) [] counter stats
= _ -- What should we do with an empty list?
Далее мы также можем использовать сопоставление шаблонов counter==0
data Statistics = MkStatistics
{ matches :: Int
, total_points :: Int
, goal_for :: Int
, goal_against :: Int
, dif :: Int
} deriving Show
emptyStatistics :: Statistics
emptyStatistics = MkStatistics 0 0 0 0 0
statistics :: [(Int,Int)] -> Statistics
statistics [] = emptyStatistics
statistics s@(x:xs) = help_statistics s x xs 0 emptyStatistics
help_statistics :: [(Int,Int)]->(Int,Int)->[(Int,Int)]->Int-> Statistics -> Statistics
help_statistics s (x,y) (hd:tl) counter@0 stats
-- When counter == 0, increase it by 1 (i.e. set it to 1)
-- Is this really what was intended?
= help_statistics s hd tl (counter 1) stats'
where stats' = stats {matches = length s} -- Update `matches` to a new value
help_statistics s (x,y) (hd:tl) counter stats
= stats -- when counter is not 0, return the stats. Was this reversed?
help_statistics s (x,y) [] counter stats
= _ -- What should we do with an empty list?
Мы также можем использовать сопоставление шаблонов, чтобы избежать наличия двух отдельных аргументов для головы и хвоста, но теперь мы немного изменили поведение
data Statistics = MkStatistics
{ matches :: Int
, total_points :: Int
, goal_for :: Int
, goal_against :: Int
, dif :: Int
} deriving Show
emptyStatistics :: Statistics
emptyStatistics = MkStatistics 0 0 0 0 0
statistics :: [(Int,Int)] -> Statistics
statistics s = help_statistics s s 0 emptyStatistics
help_statistics :: [(Int,Int)] -> [(Int,Int)] -> Int -> Statistics -> Statistics
help_statistics s ((x,y):tl) counter@0 stats
-- When counter == 0, increase it by 1 (i.e. set it to 1)
-- Is this really what was intended?
= help_statistics s tl (counter 1) stats'
where stats' = stats {matches = length s} -- Update `matches` to a new value
help_statistics s (_:_) counter stats
= stats -- when counter is not 0, return the stats. Was this reversed?
help_statistics s [] counter stats
= stats -- What should we do with an empty list?