IsPrefixOf 在模式匹配段期间无法正常工作
IsPrefixOf not working correctly during pattern matching segment
我对 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]
。但是,此类型表示 list 个字符串,而不是单个字符串。单个字符串的类型只是 String
.
因此,您对这些类型的选择有点奇怪:
type Title = [String]
type Artist = [String]
这意味着每张专辑:
type Album = (Title, Artist, Year, Sales)
有一个 Title
,它是一个 list 字符串和一个 Artist
,它是一个 list 字符串。我想我可以看出您可能想要多个艺术家(虽然这样类型可能应该以复数形式命名为 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
当调用 as 时,说:
searchByPrefix ["G"] (["Greatest Hits"],["Queen"],...)
创建参数绑定 prefx=["G"]
和 t=["Greatest Hits"]
。 isPrefixOf
调用检查 one-element 列表 ["G"]
是否是 one-element 列表 ["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
不是 one-element 列表的记录,或者如果 searchByPrefix
是用一个one-element 列表以外的前缀。 (因此额外的元素将导致运行时错误,而不是被默默地忽略。)
我对 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]
。但是,此类型表示 list 个字符串,而不是单个字符串。单个字符串的类型只是 String
.
因此,您对这些类型的选择有点奇怪:
type Title = [String]
type Artist = [String]
这意味着每张专辑:
type Album = (Title, Artist, Year, Sales)
有一个 Title
,它是一个 list 字符串和一个 Artist
,它是一个 list 字符串。我想我可以看出您可能想要多个艺术家(虽然这样类型可能应该以复数形式命名为 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
当调用 as 时,说:
searchByPrefix ["G"] (["Greatest Hits"],["Queen"],...)
创建参数绑定 prefx=["G"]
和 t=["Greatest Hits"]
。 isPrefixOf
调用检查 one-element 列表 ["G"]
是否是 one-element 列表 ["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
不是 one-element 列表的记录,或者如果 searchByPrefix
是用一个one-element 列表以外的前缀。 (因此额外的元素将导致运行时错误,而不是被默默地忽略。)