<div dir="ltr">Ha, whoops... I duplicated an error in your original because it compiles.<div><br></div><div>-- This creates a constructor named "List" which holds a single CartBasket!</div><div>data Cart = List CartBasket</div><div><br></div><div>-- You probably intended this:</div><div>type Cart = [CartBasket]</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Jul 30, 2016 at 5:55 PM, Theodore Lief Gannon <span dir="ltr"><<a href="mailto:tanuki@gmail.com" target="_blank">tanuki@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">(Apologies for any duplicates... for some reason the original's reply address is <a href="mailto:haskell-cafe@googlegroups.com" target="_blank">haskell-cafe@googlegroups.com</a> rather than <a href="mailto:haskell-cafe@haskell.org" target="_blank">haskell-cafe@haskell.org</a>, and it sent a rejection notice for my reply.)<span class=""><div><br></div><div><div dir="ltr" style="font-size:12.8px">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:<div><br></div><div><div>-- A basket is the association of an item with a count.</div><div>data Basket = Basket {item :: String, count :: Int}</div><div><br></div><div>-- Open and closed baskets are just baskets with different behavior.</div><div>newtype OpenBasket = OpenBasket {getOpenBasket :: Basket}</div><div>newtype ClosedBasket = ClosedBasket {getClosedBasket :: Basket}</div><div><br></div><div>-- A cart can contain a mix of both basket types.</div><div>type CartBasket = Either OpenBasket ClosedBasket</div><div>data Cart = List CartBasket</div><div><br></div><div>-- We'll want to conveniently inspect CartBaskets.</div><div>getCartBasket :: CartBasket -> Basket</div><div>getCartBasket = either getOpenBasket getClosedBasket</div><div><br></div><div>-- This function accepts only OpenBaskets. No need for a runtime check.</div><div>addToOpenBasket :: OpenBasket -> OpenBasket</div><div>addToOpenBasket (OpenBasket b@(Basket _ i))</div><div> = OpenBasket (b {count = i+1})</div><div><br></div><div>-- First-class functions let you keep this safety all the way to the top...</div><div>data UserControl a = UserControl {label :: String, behavior :: a -> a}</div><div><br></div><div>-- Only allow the user to see valid behaviors!</div><div>getAddToCartBasketUserControl :: CartBasket -> UserControl CartBasket<br></div><div>getAddToCartBasketUserControl =</div><div> let f = either (Left . addToOpenBasket) Right</div><div> in either (const (UserControl "Add" f)) (const (UserControl "Locked" f))</div></div><div><br></div></div></div></span></div><div class="gmail_extra"><br><div class="gmail_quote"><span class="">On Sat, Jul 30, 2016 at 3:01 PM, Gurudev Devanla <span dir="ltr"><<a href="mailto:gurudev.devanla@gmail.com" target="_blank">gurudev.devanla@gmail.com</a>></span> wrote:<br></span><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><div dir="ltr">Hello All,<br><br>I have a design question where I could use some of your thoughts and suggestions. Here is the setup. I apologize<br>for the long email but I have resisted asking this question, since it needs a long explanation, until now.<br><br>I have a set of data structures defined as follows<br><br>-- An Item that can be of two types, one whose value can be changed, one whose value are frozen once created <br>data Item = FreeToChange {freeToChangeCount:: Int}<br> | CannotChange {frozenCount:: Int}<br><br>-- The item is part of a basket<br>data Basket = Basket { name:: String, item::Item }<br><br>-- The cart can have both kind of Baskets at the start of the program, or during runtime.<br>data Cart = List Basket<br><br>You can imagine this be a shopping cart with fixed set of items. Where the count of<br>some of the items in the basket can be changed during shopping but not the count of the<br>items once they are tagged as frozen.<br><br>Therefore, valid operation are:<br><br>1. I can create an Basket with either FreeToChange item or CannotChange item.<br>2. I can update the count for FreeToChange item in the Basket<br>3. But, once I create an instance of the Basket to contain the CannotChange item,<br> we cannot update the count anymore or update the Basket.<br><br>One approach I have taken is to throw an error if this happens by pattern matching on type. But, this is <br>an runtime check.<br><br>addToBasket :: Basket -> Basket<br>addToBasket b = let<br> i = item b<br> i' = case i of<br> FreeToChange f -> FreeToChange {freeToChangeCount = f + 1}<br> CannotChange f -> error ("This operation is not allowed")<br> in<br> b {item=i'}<br><br><br>Here are my questions:<br><br>1. Is there a way to design the above data structures in such a way I could use the type system. <br>2. Since, these are runtime changes, is it even a good design pattern to push this responsibility to a type system?<br><br><br>Thanks<br>Guru<br><br><br></div><br></div></div><span class="">_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.<br></span></blockquote></div><br></div>
</blockquote></div><br></div>