[Haskell-cafe] Design Question - Functions taking 'subtype' like arguments but has to be restricted to one type

Theodore Lief Gannon tanuki at gmail.com
Sun Jul 31 00:55:06 UTC 2016

(Apologies for any duplicates... for some reason the original's reply
address is haskell-cafe at googlegroups.com rather than
haskell-cafe at 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 at gmail.com>

> 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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20160730/149ea879/attachment.html>

More information about the Haskell-Cafe mailing list