List Haskell将电话簿创建为元组列表

List Haskell将电话簿创建为元组列表,list,function,haskell,search,tuples,List,Function,Haskell,Search,Tuples,我需要创建一个电话簿作为元组列表: type Phonebook :: [(String,String)] 正如您在代码中看到的,第一个元素应该表示名称,第二个元素应该表示数字。那么 Main> phonebookone = insert "Dad" "90213" (insert "mum" "8912" emptyPhonebook) Main> phonebookone 应该是[(“爸爸”,“90213”),(“妈妈”,“8912”)]但我只得到[(“爸爸”,“90213”

我需要创建一个电话簿作为元组列表:

type Phonebook :: [(String,String)]
正如您在代码中看到的,第一个元素应该表示名称,第二个元素应该表示数字。那么

Main> phonebookone = insert "Dad" "90213" (insert "mum" "8912" emptyPhonebook)
Main> phonebookone
应该是
[(“爸爸”,“90213”),(“妈妈”,“8912”)]
但我只得到
[(“爸爸”,“90213”)]

我的代码:

emptyPhonebook :: Phonebook
emptyPhonebook = [("","")]

insert :: String -> String -> Phonebook -> Phonebook
insert name number phonebook = [(name,number)]
此外,我还需要创建一个函数
search
,该函数搜索数字或更好的结果。如果元组的第一个元素存在于列表中,并且与字符串相同,那么搜索的对象将是元组的第二个元素

因此,它应该是:

Main> search "Dad" phonebook
"90213"
我的未完成代码:

search :: String -> Phonebook -> String
search name phonebook = if ..???
insert :: String -> String -> Phonebook -> Phonebook
insert name number = (:) (name,number)

您的代码有很多问题:

  • 您的
    emptyPhonebook
    实际上并不是空的:实际上,您已经在其中定义了一个元组:名称和电话号码都是空字符串的元组。您可以将其更正为:

    emptyPhonebook :: Phonebook
    emptyPhonebook = []
    
  • 您的插入方法
    insert
    实际上创建了一个
    电话簿
    ,其中有一个条目:您要添加的条目,电话簿的其余部分将被忽略。您可以使用CONS(
    (:)
    )函数来执行以下操作:

    search :: String -> Phonebook -> String
    search name phonebook = if ..???
    
    insert :: String -> String -> Phonebook -> Phonebook
    insert name number = (:) (name,number)
    
现在回答主要问题。首先,大多数Haskell程序员认为<>代码> 是非Haskell:在Haskell中,使用模式匹配和保护来设置规则的约束。 由于您的搜索可能会在找不到具有该姓名的人时出错(您没有指定此名称),因此实际上我们必须考虑两个代码路径:

  • 其中我们得到一个非空列表,其中第一个元素与我们的搜索匹配:在这种情况下,我们返回相应的数字;及
  • 在这种情况下,我们只需在给定列表的末尾继续搜索
Haskell中的这些规则如下所示:

search query ((name,number):other) = ...
现在,如果
query
name
匹配,我们应该返回数字,以便:

search query ((name,number):other) | query == name = number
在另一种情况下,我们递归地继续我们的崇高追求:

search query ((name,number):other) | otherwise = search query other
因此,把它放在一起,你会得到:

search :: String -> Phonebook -> String
search query ((name,number):other) | query == name = number
                                   | otherwise = search query other
这将返回电话簿中给定的号码,否则返回错误

编辑

如果您希望在搜索失败时返回
“error”
(作为字符串),则只需添加一条附加规则:

search _ [] = "error"
因此,将所有这些放在一起可以得出:

search :: String -> Phonebook -> String
search query ((name,number):other) | query == name = number
                                   | otherwise = search query other
search _     [] = "error"

如前所述,您的插入功能不完整,否则无论您尝试插入什么,它都只有1条记录,因此如果您尝试在电话簿中搜索特定联系人,它将只检索1条记录。但我不会回答这个问题,因为这已经得到了回答

然后在电话簿上应用简单的递归

search :: String -> Phonebook -> String
search name ((contactName, contactNumber):phonebook) = if contactName == name then contactNumber else search name phonebook 
或者你可以使用过滤器

search :: String -> Phonebook -> String
search name phonebook = snd . head . filter ((==name) . fst) $ phonebook
第二个选项的唯一问题是,它将检索具有相同姓名的第一个联系人,而该联系人可能不是我们要查询的联系人。解决此问题的方法是,如果有多个姓名相同的个人,则使用
或字符串phonebook
作为返回类型,因此:

search :: String -> Phonebook -> Either String phonebook
search name phonebook = let getContacts nm contacts = filter ((==nm) . fst) $ contacts
                    in case (length $ getContacts name phonebook) == 1 of
                             True -> Left $ snd . head . getContacts name $ phonebook
                             False -> Right $ (getContacts name) $ phonebook

忽略最后一个,未经测试,我不认为这正是您想要的,我只是添加了这个,以防万一。实际上,您的
insert
只是丢弃现有条目。你要找的是
(姓名、号码):电话簿
,而不仅仅是
[(姓名、号码)]
你的
空电话簿实际上有一个条目。如果我没记错的话,你已经是第三个问相关问题的人了。比如说,谢谢你,米切尔!您的解决方案解决了主要问题。但是现在的结果是[(“爸爸”,“90213”),(“妈妈”,“8912”),(“,”),而不是[(“爸爸”,“90213”),(“妈妈”,“8912”)]。你知道一个更好的空电子书解决方案吗?@WillemVanOnsem哈哈我需要一个快速的名字来问我的问题,我以前看到过John Doe的问题,所以我想我受到了启发。顺便问一下,您知道一种实现函数的方法吗?该函数检查字符串是否以某些字符开头。我需要这个函数作为我的电话簿的扩展:是否有可能避免错误,并返回一个字符串来代替它?@J.Dean:字符串应该是什么样子?@J.Dean:但是在这种情况下你没有任何数字:如果找不到号码,程序会出错。我的意思是类似于| query==name=number | search query other==名称=编号|否则为“错误”。在这个错误的代码中,它只搜索第一个条目。我需要这个的正确版本,程序在列表中搜索所有元组。谢谢你的快速回答!