2017-01-19 2 views
1

мне нужно создать телефонную книгу в виде списка кортежей:Haskell создать телефонную книгу в виде списка кортежей

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, что поиск номеров или лучше, если первый элемент кортежа существует в списке и тот же, что и String, которого вы ищете, это приведет к второму элементу кортежа.

Так оно и должно быть:

Main> search "Dad" phonebook 
"90213" 

Мой незавершенной код для этого:

search :: String -> Phonebook -> String 
search name phonebook = if ..??? 
+0

Как бы то ни было, ваша 'insert' просто отбрасывает существующие записи. Вы ищете '(имя, номер): phonebook', а не просто' [(имя, номер)] ' – Michail

+0

В вашей' emptPhonebook' есть запись. –

+1

Если я правильно помню, вы уже третий, задающий связанные вопросы. См. Например [здесь] (http://stackoverflow.com/questions/41696230/haskell-phonebook-adding-elements?s=1|0.0000). –

ответ

2

Много вещей неправильно с вашим кодом:

  • Ваш emptyPhonebook на самом деле не пусто: действительно вы определили в нем один кортеж: тот, у которого есть пустая строка, как имя, так и ph один номер. Вы можете исправить это:

    emptyPhonebook :: Phonebook 
    emptyPhonebook = [] 
    
  • Ваш метод вставки insert фактически создает Phonebook с одной записью: тот, который вы хотите добавить, остальная часть телефонной книги игнорируется. Вы можете использовать функцию ((:)) CONS для этого:

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

Теперь, чтобы ответить на главный вопрос. Прежде всего, большинство Haskell программистов считают if довольно ООН -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 

Это вернет номер, присвоенный это в телефонной книге, и в противном случае ошибка.

EDIT:

Учитывая вы хотите вернуть "error" (как строка), когда поиск не удается, нужно только добавить дополнительное правило:

search _ [] = "error" 

Так положить все это вместе дает :

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

есть ли возможность избежать ошибки и вместо этого вернет строку? –

+0

@ J.Dean: как должна выглядеть строка? –

+0

что-то вроде «error» –

0

Как уже упоминалось, ваша функция вставки неполна, в противном случае независимо от того, что вы пытаетесь ввести inse rt к нему у него будет только 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 

Единственной проблема с вторым вариантом, что он будет получать первый контакт с тем же именем и это может быть не тот, к которому мы обращаемся, решением для этого было бы использовать 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 

Игнорировать последний, не проверен, и я не думаю, что это именно то, что вы хотите, я просто добавил это на всякий случай в качестве дополнительного.

Смежные вопросы