Я думаю, что у вас, возможно, сложилось впечатление, что тип для строк в Haskell - [String]
.Однако этот тип представляет список строк, а не одну строку.Тип для отдельной строки - просто String
.
. В результате, ваш выбор этих типов будет немного странным:
type Title = [String]
type Artist = [String]
Это означает, что каждый альбом:
type Album = (Title, Artist, Year, Sales)
имеет Title
, это список строк и Artist
, это список строк.Думаю, я вижу, что вам может понадобиться несколько исполнителей (хотя тогда тип, возможно, должен называться Artists
во множественном числе), но я думаю, что одной строки для названия альбома должно быть достаточно.
Причина, по которой я привожу это, заключается в том, что в вашей функции displayAlbumsByPrefix
есть двусмысленность, если в базе данных есть такая запись:
...
(["Dark Side of the Moon", "Gold CD Ultradisc Re-release"], ["Pink Floyd"], 1979, 2520000),
...
Должна ли она быть включена в список, сгенерированный displayAlbumsByPrefix ["G"]
позвонить?Или вы проверяете только префикс первой строки в списке Title
?Что если в базе данных есть запись, в которой заголовок представляет собой пустой список []
?
В любом случае, давайте оставим это в стороне и предположим, что вы хотите придерживаться своего текущего кода, что по соглашению база данных всегда будет включатьзаголовки, которые представляют собой списки ровно одной строки ["like this"]
и которые вы хотите отфильтровать по префиксу этой строки.
В этом случае вы почти у цели.Код:
searchByPrefix :: [String] -> Album -> Bool
searchByPrefix prefx (t, a, y, s)
| isPrefixOf prefx t = True
| otherwise = False
при вызове, скажем:
searchByPrefix ["G"] (["Greatest Hits"],["Queen"],...)
создает привязки аргументов prefx=["G"]
и t=["Greatest Hits"]
.Вызов isPrefixOf
проверяет, является ли одноэлементный список ["G"]
префиксом одноэлементного списка ["Greatest Hits"]
- другими словами, является ли элемент "G"
равным "Greatest Hits"
.Это ясно False
, поэтому ваш код не выполняет то, что вы хотите.Сравните следующее, чтобы увидеть, что происходит:
> isPrefixOf ["G"] ["Goo"] -- False -- string "G" is not equal to string "Goo"
> isPrefixOf "G" "Goo" -- True -- character 'G' is equal to character 'G'
Вы можете исправить это, вызвав isPrefixOf
на заголовках списков вместо самих списков:
searchByPrefix :: [String] -> Album -> Bool
searchByPrefix prefx (t, a, y, s)
| isPrefixOf (head prefx) (head t) = True -- change this line
| otherwise = False
Это будетзавершиться с ошибкой во время выполнения, если префикс или список заголовков в записи базы данных пусты, и он будет молча игнорировать любые дополнительные элементы после первого в этих списках.
Вы также можете сделать то же самое с помощьювместо совпадения с шаблоном:
searchByPrefix :: [String] -> Album -> Bool
searchByPrefix [prefx] ([t], a, y, s) -- or change this line
| isPrefixOf prefx t = True
| otherwise = False
и эта версия завершится с ошибкой времени выполнения, если база данных содержит запись с Title
, отличным от одноэлементного списка, или если вызывается searchByPrefix
с префиксом, отличным от одноэлементного списка.(Таким образом, дополнительные элементы вызовут ошибку времени выполнения, а не будут игнорироваться.)