[Haskell-cafe] self-referential data
wren ng thornton
wren at freegeek.org
Sat Aug 9 23:31:52 EDT 2008
brian wrote:
>>From https://secure.wikimedia.org/wikipedia/en/wiki/Bencoding , I
> think I should code
>
> data BValue = BString String
> | BInteger Integer
> | BList [BValue]
> | BDictionary (M.Map BString BValue)
>
> but: Not in scope: type constructor or class `BString'
>
> The implementations I've found just implemented BDictionary's map key
> as String, but I think that's kind of wrong.
Data Types a la Carte[1] seems like a good fit:
> newtype BString e = BString String
> newtype BInteger e = BInteger Integer
> newtype BList e = BList [Bvalue]
> newtype BDictionary e = BDictionary (M.Map (BString e) BValue)
>
> newtype Y f = Y { unY :: f (Y f) }
> data (f :+: g) e = Inl (f e) | Inr (g e)
>
> type BValue = Y (BString
> :+: BInteger
> :+: BList
> :+: BDictionary
> )
...with the necessary Functor instances. Or, since BString is the only
member of the coproduct that needs special treatment, you could squash
things a bit more:
> newtype BString e = BString String
> data BValue_ e = BInteger Integer
> | BList [Bvalue]
> | BDictionary (M.Map (BString e) BValue)
>
> type BValue = Y (BString :+: BValue_)
The former is more homogeneous and so would probably look prettier in
code, but the latter is a bit more efficient since it needs less
coproduct tagging and function indirection.
Of course, another approach is to just go with your first approach and
doubly wrap String. So there's a newtype BString_ = BString_ String, and
BValue has a constructor (BString BString_) and the dictionary uses the
BString_ data type.
[1] With added discussion:
http://wadler.blogspot.com/2008/02/data-types-la-carte.html
--
Live well,
~wren
More information about the Haskell-Cafe
mailing list