
@Theodore, thank you for the working example.
You did simplify the problem statement. Actually Basket itself is a more
complicated structure, with Item being one of its attributes. But, let me
go along with your simplification.
It seems to me that, your approach replaces placeholder "error" expression
I had, with a no-op on the Right value. Of course, I could switch the
right function to 'either' to do some thing more than a no-op. Is that
correct?
@Imants, @Matthias : I agree with your suggestions and that is where
@Theodore's approach was also leading to but in a different form.
Looks like unless I have 2 separate entities, one for Frozen and one for
Flexible, I will have to deal with run-time behaviour. I say this, since in
a more complicated scenario, I might want to map over a list of buckets,.
but only be able to called updated on items in the list that are of
particular type.
Thanks
Guru
On Sat, Jul 30, 2016 at 5:55 PM, Theodore Lief Gannon
(Apologies for any duplicates... for some reason the original's reply address is haskell-cafe@googlegroups.com rather than haskell-cafe@haskell.org, and it sent a rejection notice for my reply.)
If I understand your model right, the Item is just a count, and it's the Basket's 'name' field which actually says what the item is? Assuming I have that right, check this out:
-- A basket is the association of an item with a count. data Basket = Basket {item :: String, count :: Int}
-- Open and closed baskets are just baskets with different behavior. newtype OpenBasket = OpenBasket {getOpenBasket :: Basket} newtype ClosedBasket = ClosedBasket {getClosedBasket :: Basket}
-- A cart can contain a mix of both basket types. type CartBasket = Either OpenBasket ClosedBasket data Cart = List CartBasket
-- We'll want to conveniently inspect CartBaskets. getCartBasket :: CartBasket -> Basket getCartBasket = either getOpenBasket getClosedBasket
-- This function accepts only OpenBaskets. No need for a runtime check. addToOpenBasket :: OpenBasket -> OpenBasket addToOpenBasket (OpenBasket b@(Basket _ i)) = OpenBasket (b {count = i+1})
-- First-class functions let you keep this safety all the way to the top... data UserControl a = UserControl {label :: String, behavior :: a -> a}
-- Only allow the user to see valid behaviors! getAddToCartBasketUserControl :: CartBasket -> UserControl CartBasket getAddToCartBasketUserControl = let f = either (Left . addToOpenBasket) Right in either (const (UserControl "Add" f)) (const (UserControl "Locked" f))
On Sat, Jul 30, 2016 at 3:01 PM, Gurudev Devanla < gurudev.devanla@gmail.com> wrote:
Hello All,
I have a design question where I could use some of your thoughts and suggestions. Here is the setup. I apologize for the long email but I have resisted asking this question, since it needs a long explanation, until now.
I have a set of data structures defined as follows
-- An Item that can be of two types, one whose value can be changed, one whose value are frozen once created data Item = FreeToChange {freeToChangeCount:: Int} | CannotChange {frozenCount:: Int}
-- The item is part of a basket data Basket = Basket { name:: String, item::Item }
-- The cart can have both kind of Baskets at the start of the program, or during runtime. data Cart = List Basket
You can imagine this be a shopping cart with fixed set of items. Where the count of some of the items in the basket can be changed during shopping but not the count of the items once they are tagged as frozen.
Therefore, valid operation are:
1. I can create an Basket with either FreeToChange item or CannotChange item. 2. I can update the count for FreeToChange item in the Basket 3. But, once I create an instance of the Basket to contain the CannotChange item, we cannot update the count anymore or update the Basket.
One approach I have taken is to throw an error if this happens by pattern matching on type. But, this is an runtime check.
addToBasket :: Basket -> Basket addToBasket b = let i = item b i' = case i of FreeToChange f -> FreeToChange {freeToChangeCount = f + 1} CannotChange f -> error ("This operation is not allowed") in b {item=i'}
Here are my questions:
1. Is there a way to design the above data structures in such a way I could use the type system. 2. Since, these are runtime changes, is it even a good design pattern to push this responsibility to a type system?
Thanks Guru
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.