Another possibility would be to keep your definition for Location, but switch to:

data Item a = Item a
type ItemDB = Map Item Location

...and use a recursive lookup to find the location of an item contained within another. This is quite a bit simpler, but whether it's preferable probably depends on whether your more common lookup is "where is item x?" vs. "what's at location y?"

On Jun 28, 2016 2:26 PM, "Theodore Lief Gannon" <tanuki@gmail.com> wrote:
Sometimes relational is the way to go, but it's always worth looking for other options. :) The idiomatic preference, I think, would be to separate the nesting structure from the object data. The item containment graph sounds like a RoseTree, and since location is always inherited, that can just be a Map.

import qualified Data.Map as M
data Rose a = Rose a [Rose a] deriving (Eq, Show)
data Item a = Item a deriving (Eq, Show)
type ItemGraph a = Rose (Item a)
type ItemDB k a = M.Map k (ItemGraph a)

>>> let ex_itemdb = M.fromList [("a", Rose (Item 1) [Rose (Item 2) []])]
>>> M.lookup "a" ex_itemdb
Just (Rose (Item 1) [Rose (Item 2) []])

>>> let roseContains i (Rose x xs) = i == x || any (roseContains i) xs
>>> let isItemAt i l idb = maybe False id $ roseContains i <$> M.lookup l idb
>>> isItemAt (Item 2) "a" ex_itemdb
True

>>> let swapLoc l1 l2 idb = let {i1 = M.lookup l1 idb; i2 = M.lookup l2 idb} in maybe (M.delete l1) (M.insert l1) i2 . maybe (M.delete l2) (M.insert l2) i1 $ idb
>>> let moved = swapLoc "a" "b" ex_itemdb
>>> isItemAt (Item 2) "a" moved
False
>>> moved
fromList [("b",Rose (Item 1) [Rose (Item 2) []])]

There are quite a few unfinished pieces here, but hopefully it gets you thinking in new directions!

On Tue, Jun 28, 2016 at 11:39 AM, martin <martin.drautzburg@web.de> wrote:
Hello all,

I recently tried to model "Items", where an Item can either be inside another Item or at a certain location. I started
like this:

data Location i l = At l
                  | In (Item i l)
                    deriving (Eq, Show)

data Item i l     = Itm i (Location i l)
                    deriving (Eq, Show)

type ItemDb i l = [Item i l]

ex_itemdb = let i1 = Itm 1 (At "a")
                i2 = Itm 2 (In i1)
            in [i1, i2]

Now I wanted to move Item 1 to a different location using this code:

moved = fmap f ex_itemdb
        where
            f (Itm 1 (At "a")) = (Itm 1 (At "b"))
            f x = x

Not this does not do what I want. I get

-- *Main> ex_itemdb
-- [Itm 1 (At "a"),Itm 2 (In (Itm 1 (At "a")))]

-- *Main> moved
-- [Itm 1 (At "b"),Itm 2 (In (Itm 1 (At "a")))]

While Item 1 has moved to "b" Item 2 still claims to be in an "Itm 1 (At "a")". I understand what's going on here and
coming from a DB background I can see that the redundant data is the root of the problem.

I can model this in a relational way such that the redundancy is avoided. But maybe there is a more haskellish/idiomatic
way to acomplish this.

Is there?

_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners