<div dir="ltr">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.<div><br></div><div>import qualified Data.Map as M</div><div>data Rose a = Rose a [Rose a] deriving (Eq, Show)<br></div><div>data Item a = Item a deriving (Eq, Show)<br></div><div>type ItemGraph a = Rose (Item a)<br></div><div>type ItemDB k a = M.Map k (ItemGraph a)<br></div><div><br></div><div>>>> let ex_itemdb = M.fromList [("a", Rose (Item 1) [Rose (Item 2) []])]</div><div>>>> M.lookup "a" ex_itemdb<br></div><div>Just (Rose (Item 1) [Rose (Item 2) []])</div><div><br></div><div>>>> let roseContains i (Rose x xs) = i == x || any (roseContains i) xs</div><div>>>> let isItemAt i l idb = maybe False id $ roseContains i <$> M.lookup l idb</div><div>>>> isItemAt (Item 2) "a" ex_itemdb</div><div>True</div><div><br></div><div>>>> 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</div><div>>>> let moved = swapLoc "a" "b" ex_itemdb<br></div><div>>>> isItemAt (Item 2) "a" moved</div><div>False</div><div>>>> moved</div><div>fromList [("b",Rose (Item 1) [Rose (Item 2) []])]<br></div><div><br></div><div>There are quite a few unfinished pieces here, but hopefully it gets you thinking in new directions!</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jun 28, 2016 at 11:39 AM, martin <span dir="ltr"><<a href="mailto:martin.drautzburg@web.de" target="_blank">martin.drautzburg@web.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello all,<br>
<br>
I recently tried to model "Items", where an Item can either be inside another Item or at a certain location. I started<br>
like this:<br>
<br>
data Location i l = At l<br>
| In (Item i l)<br>
deriving (Eq, Show)<br>
<br>
data Item i l = Itm i (Location i l)<br>
deriving (Eq, Show)<br>
<br>
type ItemDb i l = [Item i l]<br>
<br>
ex_itemdb = let i1 = Itm 1 (At "a")<br>
i2 = Itm 2 (In i1)<br>
in [i1, i2]<br>
<br>
Now I wanted to move Item 1 to a different location using this code:<br>
<br>
moved = fmap f ex_itemdb<br>
where<br>
f (Itm 1 (At "a")) = (Itm 1 (At "b"))<br>
f x = x<br>
<br>
Not this does not do what I want. I get<br>
<br>
-- *Main> ex_itemdb<br>
-- [Itm 1 (At "a"),Itm 2 (In (Itm 1 (At "a")))]<br>
<br>
-- *Main> moved<br>
-- [Itm 1 (At "b"),Itm 2 (In (Itm 1 (At "a")))]<br>
<br>
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<br>
coming from a DB background I can see that the redundant data is the root of the problem.<br>
<br>
I can model this in a relational way such that the redundancy is avoided. But maybe there is a more haskellish/idiomatic<br>
way to acomplish this.<br>
<br>
Is there?<br>
<br>
_______________________________________________<br>
Beginners mailing list<br>
<a href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners</a><br>
</blockquote></div><br></div>