Использование фильтра для элемента в списке?

#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. Хорошо, я попробую это, я новичок в этом, как бы мне заставить его возвращать строку, я думал, что это уже было?