我是Haskell的新手。我有一个充当数据库的列表,我想用你可以插入的前缀搜索列表的标题。标题的类型数据是[String]
最后设法使代码编译,但不是搜索前缀,该函数仅在插入完整标题时才有效。所以例如我想搜索[“G”]并弹出两个结果,但除非输入完整的标题,否则搜索没有结果。
-- Types
type Title = [String]
type Artist = [String]
type Year = Int
type Sales = Int
-- Define Album type here
type Album = (Title, Artist, Year, Sales)
-- Define database type here
type Database = [Album]
然后数据库遵循这种模式
[(["Greatest Hits" ], [ "Queen" ], 1981, 6300000),
(["Gold: Greatest Hits" ], [ "ABBA" ], 1992, 5400000),
...
-
- Detects if the prefix is in the string ahead of it
searchByPrefix :: [String] -> Album -> Bool
searchByPrefix prefx (t, a, y, s)
| isPrefixOf prefx t = True
| otherwise = False
-- A function that displays all the albums by a certain artist
displayAlbumsByPrefix :: [String] -> Database -> String
displayAlbumsByPrefix prefx database = albumsToString (filter (searchByPrefix (prefx)) database)
albumsToString只是一个整齐地显示数据库的函数。
我理解这个问题可能是一次大规模的疏忽。
我想你可能会形成一种印象,即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
,则此版本将因运行时错误而失败。 (因此额外的元素将导致运行时错误,而不是被忽略。)