<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>This sounds like a perfect opportunity to use phantom types. I'll
be using it's DataKind-enhanced variant for added beauty.</p>
<blockquote
cite="mid:8ed829cc-3f7b-407d-a1cb-fd66785ac60a@googlegroups.com"
type="cite">
<div dir="ltr">-- 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>
</div>
</blockquote>
<p>I assume all items are equal apart from their changeability. Not
that it's necessary, but it makes the demonstration simpler. If
changeable and unchangeable items have differing structure you may
need additional tools like smart constructors. Accordingly, my
items have the type</p>
<pre> data PlainItem = PlainItem { count :: Int }
</pre>
<p>Changeability will be added on top:<br>
</p>
<pre> data Changeability = Changeable | Unchangeable
data Item (c :: Changeability) = Item { plainItem :: PlainItem }
</pre>
<p>Why separate <i>Item</i> and <i>PlainItem</i>? One second,
please.<br>
</p>
<blockquote
cite="mid:8ed829cc-3f7b-407d-a1cb-fd66785ac60a@googlegroups.com"
type="cite">
<div dir="ltr">-- The item is part of a basket<br>
data Basket = Basket { name:: String, item::Item }<br>
</div>
</blockquote>
<pre> data Basket c = Basket { name :: String, item :: Item c } -- No kind signature necessary. Thanks, solver.
</pre>
<blockquote
cite="mid:8ed829cc-3f7b-407d-a1cb-fd66785ac60a@googlegroups.com"
type="cite">
<div dir="ltr">Therefore, valid operation are:<br>
<br>
1. I can create an Basket with either FreeToChange item or
CannotChange item.<br>
</div>
</blockquote>
<br>
The new <i>Basket</i> constructor can do that by default.<br>
<br>
<blockquote
cite="mid:8ed829cc-3f7b-407d-a1cb-fd66785ac60a@googlegroups.com"
type="cite">
<div dir="ltr">2. I can update the count for FreeToChange item in
the Basket<br>
</div>
</blockquote>
<pre> changeItem :: (PlainItem -> PlainItem) -> Item 'Changeable -> Item 'Changeable</pre>
<pre> changeItem f (Item i) = Item (f i)</pre>
<pre>
changeBasket :: (PlainItem -> PlainItem) -> Basket 'Changeable -> Basket 'Changeable</pre>
<pre> changeBasket f basket@Basket{..} = basket { item = changeItem f item }</pre>
<br>
And that's why <i>PlainItem</i> was separated, so we can have a
simple type signature here. You might worry that it was exposed, but
it will not give anyone access to a frozen basket. And of course you
are free to further restrict access to it. And as we're speaking
about freezing, that's extremely simple as well.<br>
<pre> freezeItem :: Item c -> Item 'Unchangeable</pre>
<pre> freezeItem (Item i) = Item i</pre>
<pre>
freezeBasket :: Basket c -> Basket 'Unchangeable</pre>
<pre> freezeBasket basket@Basket{..} = basket { item = freezeItem item }
</pre>
<p>You later mention that you might want to map updates only over
some of the baskets in a cart. That's not hard either. As an
example, here's a way to implement a function that updates
changeable baskets while ignoring unchangeable ones:</p>
<pre> class MaybeUpdateBasket c where
updateBasket :: (PlainItem -> PlainItem) -> Basket c -> Basket c
instance MaybeUpdateBasket 'Changeable where
updateBasket = changeBasket
instance MaybeUpdateBasket 'Unchangeable where
updateBasket _ = id
</pre>
<p>Just <i>map</i> it over your cart as always.<br>
</p>
<p>If you want more complicated things (eg. you want a cart to
freeze once any bucket freezes) you just have to expand the ideas
here. You may need MultiParamTypeClasses and
FunctionalDependencies, but the basic ideas are the same.</p>
<p>Cheers.<br>
</p>
<pre></pre>
</body>
</html>