[Haskell-cafe] Design Question - Functions taking 'subtype' like arguments but has to be restricted to one type
Guru Devanla
gurudev.devanla at gmail.com
Sun Jul 31 13:24:39 UTC 2016
@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 <tanuki at gmail.com>
wrote:
> (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> 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.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20160731/a2d7c555/attachment.html>
More information about the Haskell-Cafe
mailing list