Haskell创建一个电话簿作为元组列表

时间:2017-01-19 18:54:06

标签: list function haskell search tuples

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

type Phonebook :: [(String,String)]

正如您在代码中看到的那样,第一个元素应该代表名称,第二个元素代表数字。所以

的结果
Main> phonebookone = insert "Dad" "90213" (insert "mum" "8912" emptyPhonebook)
Main> phonebookone

应为[("Dad","90213"),("mum","8912")]但我只能获得[("Dad","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 ..???

2 个答案:

答案 0 :(得分:2)

你的代码有很多问题:

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

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

    insert :: String -> String -> Phonebook -> Phonebook
    insert name number = (:) (name,number)
    

现在回答主要问题。首先,大多数Haskell程序员认为if更像是 un -Haskell:在Haskell中,使用模式匹配 guards 来设定规则约束。

由于您的搜索可能在找不到具有该名称的人时发生错误(您没有指定),实际上我们必须考虑两个代码路径:

  • 我们被赋予非空列表的位置,其中第一个元素与我们的搜索匹配:在这种情况下,我们返回相应的数字;和
  • 名称不匹配的那个,在这种情况下,我们只是继续搜索给定列表的尾部。

Haskell中的这些规则如下:

search query ((name,number):other) = ...

现在,如果queryname匹配,我们应该返回数字:

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 :(得分:0)

如前所述,您的插入功能不完整,否则无论您尝试插入哪个功能,它都只有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

第二个选项的唯一问题是它将检索具有相同名称的第一个联系人,它可能不是我们要查询的那个,解决方法是使用Either String 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

忽略最后一个,未经测试,我认为不是你想要的,我只是添加了这个以防万一。“