2013-12-13 1 views
1
type Dictionary = [(String, String)] 

dict :: Dictionary 
dict = ("Deutsch", "English"):[] 

insert :: Dictionary -> (String,String) -> Dictionary 
insert dict entry = dict ++ [entry] 

Одна вещь, которую я не нашел о том, как списки работы: Является ли это как-то можно переписать существующий Dict с записью добавленной вставки? Или необходимо, чтобы на следующем этапе всегда выписывать список, который был вынут вставкой?Функциональность добавления в списки в Haskell/перезаписи существующего списка

insert [("German", "English"), ("Hallo", "hello")] ("Versuch", "try") 

До сих пор это единственный способ, которым я был в состоянии что-то добавить в новый список, не теряя при этом предыдущую запись. Тем не менее, следующий в списке вещей для реализации - команда поиска, поэтому я задаюсь вопросом, должен ли я также записать это в функции поиска.

+0

Что именно вы подразумеваете под словом «написать это»? Кстати, жесткая сторона вашей функции вставки будет лучше просто «entry: dict» – Ingo

+0

Если вы создаете список ассоциаций, если вы вставляете в начале списка, вам не нужно удалять предыдущие потому что любой поиск найдет элемент, добавленный совсем недавно. – Lee

+0

Я уже пробовал использовать оператор cons, но, похоже, мой список, поскольку он стоит, не является списком ассоциаций? Поскольку я сталкиваюсь с той же проблемой, когда я меняю оператор из ++ на:, все, что я когда-либо получал, было одной дополнительной записью, не переименовывая все, как в примере RasmusWriedtLarsen. @Ingo Что я имел в виду, это НЕ давать имена новых списков с let dict2 и так далее, а скорее написать весь список со своими записями, как в команде вставки, которую я написал в моем вопросе. – dschib

ответ

2

Идея функционального программирования заключается в том, что ваши данные неизменяемы. Это означает, что после создания списка вы никогда не сможете изменить этот список. Но вы можете скопировать этот список, внести изменения в него и сохранить это.

Так что, когда у вас есть список, как так

test = [1,2,3] 

Мы можем изменить это путем добавления 4 к началу:

test2 = 4 : test 

: называется оператор минусам, помещает элемент перед список.Обратите внимание, что x:xs (так же, как делает [x]++xs) имеет более высокую производительность, чем делать xs++[x]

Так что теперь у нас есть два крепления, один из test в [1,2,3] и один из test2 в [4,1,2,3]

Надеются, что это проясняет вещи


Чтобы дать полный пример:

type Dictionary = [(String, String)] 

insert :: Dictionary -> (String,String) -> Dictionary 
insert dict entry = dict ++ [entry] 

dict0 = [ ("Deutsch", "English") ] 
dict1 = insert dict0 ("Hallo", "hello") 
dict2 = insert dict1 ("Versuch", "try") 

Если вы новичок в функциональном программировании, я бы рекомендовал прочитать Learn You a Haskell for Great Good, что является фантастической (и бесплатной) книгой о том, как использовать Haskell - и функциональное программирование в целом.

+0

Если я попытаюсь сделать это в командной строке, мне нужно будет добавить сначала, правильно? например 'let dict1 = insert dict0 (« Hallo »,« Hello »)'? – dschib

+0

@dschib Да, это правильно. –

+0

dict ++ [entry] - добавление одного элемента в конец списка очень плохо с точки зрения производительности. Почему бы просто не использовать оператор двоеточия? – user3974391

1

Это не слишком сложно сделать это

import Data.List (lookup) 

insert :: Eq a => (a,b) -> [(a,b)] -> [(a,b)] 
insert (a,b) []   = [(a,b)] 
insert (a,b) ((c,d):rest) = if a == c 
    then (a,b) : rest 
    else (c,d) : insert (a,b) rest 

--- 

dict :: [(String, String)] 
dict = [("Deutsch", "English")] 

Если вы не можете использовать Data.List, то вы можете определить lookup по

lookup :: Eq a => a -> [(a,b)] -> Maybe b 
lookup _ []   = Nothing 
lookup k ((a,b):rest) = if k == a then Just b else lookup k rest 

Теперь, если вы загрузите GHCI:

>> let dict' = insert ("Ein","One") dict 
>> dict' 
[("Deutsch","English"),("Ein","One")] 
>> lookup "Ein" dict' 
Just "One" 
>> insert ("Deutsch", "Francais") dict' 
[("Deutsch","Francais"),("Ein","One")] 
+0

Дело в этой задаче - не делать этого с Data.List, так как мы не так уж далеки и все еще должны разбираться в основах функционального программирования. – dschib

+0

@dschib Я отредактировал, чтобы удалить зависимость от 'Data.List' –

+0

Большое спасибо, функция поиска поможет мне значительно! – dschib

0

Если вы хотите заменить существующую пару одним и тем же ключом, вы можете написать вставку т как:

insert :: Dictionary -> (String, String) -> Dictionary 
insert [] p = [p] 
insert ((dk, dv):ps) [email protected](k, v) | dk == k = p:ps 
insert (p:ps) ip = p : (insert ps ip) 

Однако, если вы пишете ассоциативный список, то вы можете упростить его, вставляя новые элементы в передней части списка:

insert :: Dictionary -> (String, String) -> Dictionary 
insert = flip (:) 

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

0

В Haskell большинство значений неизменяемо, что означает, что вы не можете изменить их значение. Сначала это кажется огромным ограничением, но на самом деле это упрощает рассуждение о вашей программе, особенно при использовании нескольких потоков.

Что вы можете сделать, вместо того, чтобы постоянно называть insert по словарю возвращается при вызове insert, например:

mainLoop :: Dictionary -> IO() 
mainLoop dict = do 
    putStrLn "Enter the German word:" 
    german <- getLine 
    putStrLn "Enter the English word: 
    english <- getLine 
    let newDict = insert dict (german, english) 
    putStrLn "Continue? (y/n)" 
    yesno <- getChar 
    if yesno == 'y' 
     then mainLoop newDict 
     else print newDict 

main = do 
+0

Я хотел бы работать с IO, однако это далеко не так, как мы сейчас находимся в нашей лекции. Все, что нам нужно сделать, это использовать команду insert в командной строке без подсказок или чего-то подобного. Основная проблема, с которой я столкнулся с пониманием этого, заключается в том, что в любом случае, чтобы dict не был непреложным, но я думаю, это похоже на попытку бросить жемчуг перед свиньями. – dschib

+0

Не без ИО. Вы можете использовать государственную монаду, но если IO находится за пределами ваших текущих лекций, это тоже. Прямо сейчас вам просто нужно будет переделать его, как предлагает @RasmusWriedtLarsen. – bheklilr

0

Один просто не может «переписать» что-нибудь в чистом языке (за пределами ST монады). Если я правильно понял ваш вопрос, вы ищете что-то вроде этого:

insert :: Dictionary -> (String,String) -> Dictionary 
insert [] b = [b] -- If this point is reached where wasn't matching key in dictionary, so we just insert a new pair 
insert ([email protected](k, v) : t) [email protected](k', v') 
    | k == k' = (k, v') : t  -- We found a matching pair, so we 'update' its value 
    | otherwise = h : insert t b 
+0

Проверка на наличие дубликатов не требуется в моей задаче, основная проблема, с которой я столкнулся с моим пониманием, - это увидеть, как каждый определяемый мной dict неизменен, так что, если я хочу иметь новое имя для dict, у которого есть более одного я должен был бы использовать 'let dict3 = insert dict2 (« This »,« that »)'. – dschib

+0

@dschib Вы можете использовать государственную монаду для моделирования переменных. – user3974391

+0

Снова, что-то, что я могу найти в будущем, последнее, что у нас было в нашей лекции, было массивами, а монады прошли долгий путь по дороге ... – dschib