IsPrefixOf在模式匹配段期间无法正常工作

问题描述 投票:-2回答:1

我是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只是一个整齐地显示数据库的函数。

我理解这个问题可能是一次大规模的疏忽。

string haskell prefix
1个回答
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,则此版本将因运行时错误而失败。 (因此额外的元素将导致运行时错误,而不是被忽略。)

© www.soinside.com 2019 - 2024. All rights reserved.