我对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只是一个整洁地显示数据库的函数。
我知道这个问题可能是一个巨大的疏忽。
答案 0 :(得分:1)
我认为您可能已经形成一种印象,即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
的前缀不是a,则此版本将因运行时错误而失败。一元素列表。 (因此,多余的元素将导致运行时错误,而不是被忽略。)