Functionality of adding to lists in Haskell / overwriting an existing List

二次信任 提交于 2019-12-24 13:13:10

问题


type Dictionary = [(String, String)]

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

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

One thing that I didn't find about the way lists work: Is it somehow possible to overwrite the existing dict with the entry added in insert? Or is it necessary to, in the next step, always write out the list that was put out by insert?

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

So far, this is the only way I have been able to add something to the new list without losing the previous entry. However, next on the list of things to implement is a search command, so I wonder if I'd also have to write this out in the search function.


回答1:


The idea of functional programming is in general that your data is immutable. This means once you have created a list, you can NEVER change that list. But you can copy that list, make modifications to it, and keep that as well.

So when you have a list like so

test = [1,2,3]

We can modify this by adding 4 to the start:

test2 = 4 : test

: called the cons operator, puts an element in front of a list. Do note that x:xs (the same as doing [x]++xs) has a better performance than doing xs++[x]

So now we have two bindings, one of test to [1,2,3] and one of test2 to [4,1,2,3]

Hope this clarifies things


To give a full example:

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")

If you're new to functional programming, I would recommend reading Learn You a Haskell for Great Good , which is a fantastic (and free) book on how to use Haskell -- and functional programming in general.




回答2:


It's not too tough to do this

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")]

If you can't use Data.List then you can define lookup by

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

Now if you load up 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")]



回答3:


If you want to replace an existing pair with the same key then you could write insert as:

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

However if you are writing an association list, then you can simplify it by inserting new items at the front of the list:

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

if you then search from the front of the list, it will find any values added more recently first.




回答4:


In Haskell, most values are immutable, meaning that you can not change their value. This seems like a huge constraint at first, but in reality it makes it easier to reason about your program, especially when using multiple threads.

What you can do instead is continually call insert on the dictionary returned when you call insert, for example:

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



回答5:


One simply can't 'overwrite' anything in a pure language (outside of ST monad). If I understood your question correctly, you are looking for something like this:

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 (h@(k, v) : t) b@(k', v')
    | k == k'   = (k, v') : t      -- We found a matching pair, so we 'update' its value
    | otherwise = h : insert t b


来源:https://stackoverflow.com/questions/20567255/functionality-of-adding-to-lists-in-haskell-overwriting-an-existing-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!