
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?

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

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"
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
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
participants (2)
-
martin
-
Theodore Lief Gannon