Search code examples
haskelldata-structuresrecords

How to represent and update bidirectional references in Haskell?


How can I generalize non-trivial record updates? Here is simple example that explicitly updates item references to their new owner.

data Owner = Owner {
        items :: [Item]
          } deriving (Show)

data Item = Item {
        name :: String,
        owner :: Owner
          }   

instance Show Item where
        show (Item name _) = name

item1 = Item "a" owner1
item2 = Item "b" owner1
item3 = Item "c" owner1
owner1 = Owner [item1,item2,item3,Item "d" owner1]

owner2 = Owner $ map (\(Item n o) -> Item n owner2) $ items owner1

Solution

  • Note that in Haskell values are immutable, so you can't change the value of owner1 or item1.

    I think the data structure you are looking for is Map OwnerId [Item] - i.e. a map whose keys are some owner id (a String or Int) and whose values are lists of items (the items owned by the owner):

    type OwnerId = Int -- or String
    data Item = Item { owner :: OwnerId, name :: String }
    
    type WhoOwnsWhat = Map OwnerId [Item]
    

    When you change the owner of an item you are really creating a new map by updating the two map entries with the new list of items. To reassign an item you specify the current map of who owns what, the item and the new owner and get back a new map of who owns what:

    changeOwner :: WhoOwnsWhat -> Item -> OwnerId -> WhoOwnsWhat
    

    Adding a new item involves a function like:

    addItem :: WhoOwnsWhat -> Item -> WhoOwnsWhat
    

    Note that in each case we are creating a new map.