
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.

On Sat, Aug 09, 2008 at 05:09:06PM -0500, 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.
The problem is that BString is not a type, it is a data constructor. You could use M.Map BValue BValue, but of course that's probably not what you want either. What's wrong with just using 'String' as the Map key? -Brent

On Sat, Aug 9, 2008 at 5:18 PM, Brent Yorgey
The problem is that BString is not a type, it is a data constructor.
I know.
You could use M.Map BValue BValue, but of course that's probably not what you want either.
Right. That wouldn't be according to spec either.
What's wrong with just using 'String' as the Map key?
It seems wrong. Yeah, it's just a String, but we're being all abstract because that's better practice. It happens that when you parse bencoded data, the length of the string is given. Maybe I want to store that in BString, too. But mainly I want to know how to think about it differently so that I know what to do when it comes up again and actually matters.

brian wrote:
On Sat, Aug 9, 2008 at 5:18 PM, Brent Yorgey
wrote: The problem is that BString is not a type, it is a data constructor.
I know.
You could use M.Map BValue BValue, but of course that's probably not what you want either.
Right. That wouldn't be according to spec either.
What's wrong with just using 'String' as the Map key?
It seems wrong. Yeah, it's just a String, but we're being all abstract because that's better practice. It happens that when you parse bencoded data, the length of the string is given. Maybe I want to store that in BString, too.
But mainly I want to know how to think about it differently so that I know what to do when it comes up again and actually matters.
What about using a type parameter: data BValue bString = BString bString | BInteger Integer | BList [BValue bString] | BDictionary (Map bString (BValue bString)) Regards, Maciej

brian
What's wrong with just using 'String' as the Map key? It seems wrong. Yeah, it's just a String, but we're being all abstract because that's better practice. It happens that when you parse bencoded data, the length of the string is given. Maybe I want to store that in BString, too.
So, why not just type BString_ = String data BValue = BString BString_ | BDictionary (Map BString_ BValue) you always can change BString_ to obtain a different representation for a) String values in you BValues and b) keys in your BDictionary at the same time. The "BString" data constructor means "This BValue is something called BString, oh, and, by the way, there is a string stored here". It does not mean at all that "BString" somehow represents the String type. So it really makes no sense as parameter to the Map. Just imagine, what would happen, if the BString constructor has more than one parameter. What should be the key for the map in that case? If you want to add a layer of abstraction, use a newtype instead of the type alias. But that means, standard string functions don't work on BString_ anymore. On the other hand, you are right that there is no really simple sum type notation in haskell, like "a BValue(type) is either a BString(type), a BInteger(type) or a BDictionary(type)", but you have to say the more verbose variant: "a BValue(type) is constructed in on of the following ways: a mark called BString(data constructor) accompanied by a String; a mark called BInteger(data constructor) accompanied by an Integer or a mark called BDictionary(data constructor) accompanied by a Map." These marks are surely no types. Your intuition seems more like what the other poster also suggests: data BString = BString String data BInteger = BInteger Integer data BDictionary = BDictionary (Map BString BValue) data BValue = BVString BString | BVInteger BInteger | BVDictionary BDictionary There just is no way around the data constructors (called BV...), even if they seem kind-of redundant. You might want to use newtype instead of data in the first three definitions to reduce runtime overhead, or even use type aliases for added convenience in trade for abstraction. Regards, Michael Karcher

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
participants (5)
-
Brent Yorgey
-
brian
-
Maciej Podgurski
-
usenet@mkarcher.dialup.fu-berlin.de
-
wren ng thornton