[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