#list #haskell #filter
#Список #haskell #Фильтр
Вопрос:
Я пытаюсь выполнить фильтрацию по элементу в списке и распечатать их построчно. Вот мой код:
data Car = Car String [String] Int [String]
testDatabase :: [Car]
testDatabase = [Car"Casino Royale" ["Daniel Craig"] 2006 ["Garry", "Dave", "Zoe", "Kevin", "Emma"],Car"Blade Runner" ["Harrison Ford", "Rutger Hauer"] 1982 ["Dave", "Zoe", "Amy", "Bill", "Ian", "Kevin", "Emma", "Sam", "Megan"]]
formatCarRow (Car a b c d) = show a " | " concat [i ", " | i <- init b] last b " | " show c " | " concat [j ", " | j <- init d] last d
displayFilmsByYear :: String -> IO [()]
displayFilmsByYear chosenYear = mapM (putStrLn.formatFilmRow) [putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase] -- This is the code not working i think
Почему это не работает?
Комментарии:
1. Ты имел в виду
data Film = Car …
? В противном случае происходит несоответствие типовtestDatabase
. Аналогично дляformatFilmRow
/formatCarRow
.2. я отредактировал это сейчас, извините, это была не проблема, исходная проблема все еще существует :/
3. Просто из любопытства: используете ли вы генератор случайных чисел для принятия решения о размещении слова putStrLn в тексте вашей программы? Просто шучу …. 🙂
4. пожалуйста, рассмотрите возможность разделения вашей программы на множество более мелких функций. Тогда вы сможете мыслить яснее. Даже если конкретная проблема здесь в чем-то другом, как только вы упорядочите свой код, ошибка, надеюсь, проявится сама собой.
Ответ №1:
Если вы хотите отфильтровать список, я рекомендую использовать filter
функцию 🙂
data Car = Car String [String] Int [String]
year :: Car -> Int
year (Car _ _ y _) = y
filterByYear :: Int -> [Car] -> [Car]
filterByYear chosenYear cars = filter (car -> year car == chosenYear) cars
showCar :: Car -> String
showCar car = undefined -- you can implement this how you like
displayCarsByYear :: Int -> IO ()
displayCarsByYear chosenYear = mapM_ (putStrLn . showCar) filteredCars
where filteredCars = filterByYear chosenYear testDatabase
Кажется разумным объяснить здесь несколько вещей:
Анонимные функции: (car -> year car == chosenYear)
является анонимной функцией. Он принимает один аргумент и вызывает его car
. Затем он определяет, равен ли год выпуска этого автомобиля chosenYear
. Я явно не писал сигнатуру типа этой функции, но она есть Car -> Bool
.
Фильтрация: я предоставил эту функцию filter
, чтобы она просматривала список Car
элементов. Когда filter
находит автомобили, для которых возвращает эта функция True
, она помещает их в список результатов. False
Результат означает, что машина не проходит через фильтр.
Композиция функций: (putStrLn . showCar)
Это функция, которая сначала выполняет showCar
, а затем использует putStrLn
результат showCar
.
Где: Вы заметите where
инструкцию в конце моего кода. Это должно быть достаточно понятным, вы можете использовать операторы let
or where
для определения «локальных переменных». На вкус я предпочитаю where, а не let .
Сжатие списка по сравнению с фильтром: Понимание списка может фильтровать список точно так же, как функция filter. Для функции f :: a -> Bool
и списка xs :: [a]
filter f xs
то же самое, что [x | x <- xs, f x]
. В таких случаях я предпочитаю указывать по буквам filter
, поскольку это очень ясно показывает, что я фильтрую список.
Смотрите также LYAH # Карты и фильтры
—
Дополнительная рекомендация: используйте синтаксис записи
Вместо
data Car = Car String [String] Int [String]
Почему бы и нет
data Film = Film { name :: String
, actors :: [String]
, released :: Int
, characters :: [String]
}
(Я не мог точно сказать, каким был ваш последний список строк)
Таким образом, вы можете создать фильм, подобный этому:
lotr :: Film
lotr = Film { name = "Lord of the Rings"
, actors = ["Elijah Wood", "Ian McKellen", "Orlando Bloom"]
, released = 2001
, characters = ["Frodo", "Sam", "Pippin", "Merry"]
}
И у вас автоматически появляются функции доступа
released :: Film -> Int
name :: Film -> String
- и так далее
Смотрите также Синтаксис LYAH # Record
Комментарии:
1. Haskell / Обучающий гений — вы не представляете, сколько помощи, сколько смысла и многому вы только что научили меня. Большое вам спасибо!
Ответ №2:
Суть в этом:
[putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase]
Вы еще не поняли, что такое понимание списка.
Что вы хотите, так это:
[ (Car w x y z) | (Car w x y z) <- testDatabase, y==choosenYear]
Возможно.
С
mapM (putStrLn . formatCarRow)
вы уже заказали: отформатируйте и затем распечатайте каждый элемент следующего списка. Следовательно, понимание putStrLn в списке совершенно абсурдно.
Пожалуйста, обратите внимание, что putStrLn — это в некотором роде неправильное название: на самом деле он ничего не напечатает! Он просто создает вещь, которая вызывает печать при выполнении в монаде ввода-вывода. Кажется, что это трудно понять, но скоро вы поймете.
Комментарии:
1. @Ingo: спасибо за ответ (смеюсь над комментарием выше, это за другую часть работы, поэтому мне пришлось изменить имена переменных : / ) вот ошибка, которую я получил сейчас: — Ошибка типа в генераторе *** Термин: (w, x, y, z) *** Тип: (a, b, c, d) *** Не соответствует: Film
2. Смотрите мое исправление. Пропустил, что у вас есть конструктор данных. (Разве вчера это не был кортеж?)
3. это был кортеж, но я изменил его на ‘data’, а не на ‘type’, похоже, что с другими функциями, которые мне приходилось выполнять, кода намного меньше, я изо всех сил пытаюсь понять это, все, что я хочу сделать, это то, что вы сделали выше, но вызовите ‘formatCarRow’, чтобы отформатировать строку определенным образом для печати — я должен сделать это способом, подобным этому, без дополнительных библиотек, которые могли бы сделать это за меня :/
4. В чем проблема замены formatFilmRow на formatCarRow? Если я могу дать вам совет: не делайте все сразу (форматирование, обработка списков элементов, выполнение ввода-вывода). Начните писать formatCarRow или как вы это называете, который берет Car и возвращает (не: печатает !!!) строка. Протестируйте эту функцию в ghci. Если вы довольны результатом, вернитесь и задайте вопрос: у меня есть функция Car -> String, как мне распечатать список автомобилей.
5. Хорошо, я попробую это, я новичок в этом, как бы мне заставить его возвращать строку, я думал, что это уже было?