Thanks to the discussion on this list, I now see that there are not four but five types to be distinguished in text processing: 1. Octets. 2. C "char". 3. Unicode code points. 4. Unicode code values, useful only for UTF-16, which is seldom used. 5. "What handles handle". The new entry in the list is the last one. Wolfgang Jeltsch mentioned "Stream_Element" in Ada 95, which I don't know specifically about but sounds like the same idea. I suggest that the following Haskell types be used for the five items above: 1. Word8 2. CChar 3. CodePoint 4. Word16 5. Char On most machines, Char will be a wrapper around Word8. (This contradicts the present language standard.) Let me elaborate. Files are funny because the information units they contain can be treated as both numbers and characters. Treating these units as numbers, we can convert them to say octets and use them to serialize higher-level data structures such as directed acyclic graphs, bitstrings, and Unicode text. Treating the same units as characters, we can concatenate text like "cat" does, strip out or replace selected characters like "tr" does, or compute the number of units in a stream like "wc -c" does. When we treat a file as containing characters (rather than numbers), we are in effect using a funky character encoding. This encoding is not UTF-8, not ISO-8859-1, and not ASCII. The specifics of this encoding depends on the machine. On mine, it supports 256 characters, mapped to the numbers 0 through 255. Between 0 and 127 is ASCII. From 128 to 255 are 128 additional characters -- let's call them "#128" through "#255". These characters are completely new. For example, "á" is not "#225", just like the integer "225" and the unique complete graph with 225 vertices are not the character "#225", either. Many people will never worry about the characters #128 through #255. This is akin to the fact that the characters "a" through "z" does not concern a program that reads two numbers (in decimal, textual form) from standard input, adds them up, and prints the result to standard out (again in decimal, textual form). As long as the set of characters handled by standard input and standard output includes the decimal digits, the period, and whitespace, the program will work. What do the five Haskell types proposed above mean for the practical programmer? The types in the Haskell IO library will not change; for instance, the only way to read an information unit from a handle is hGetChar :: Handle -> IO Char As I mentioned above, Char under the present proposal is not the type of a Unicode character, but the type of an information unit handled by handles, contra the current language standard. There should, however, be a basic guarantee on how big this information unit is; a reasonable one to make is that it contains at least 8 bits. In other words, ord (chr i) == i for all i such that 0 <= i <= 255. CChar will be a synonym for Char on most systems, just like CInt is a synonym for Int on most systems. I don't know if the sockets library should use Word8 or Char, but it should be one of the two. Now for the tricky issue of converting and defaulting and guessing encodings. In short: Encodings should be handled separately from files. Encoding conversion should be in a library separate from the I/O library. Without involving I/O, I should be able to write a program to answer the question "how many 3-byte sequences are valid UTF-8 text?". We will want stuff in the library like data Encoding text code = Encoding { encode :: [text] -> Maybe [code] , decode :: [code] -> Maybe [text] } utf8 :: Encoding CodePoint Word8 iso88591 :: Encoding CodePoint Word8 as well as char :: Encoding Char Word8 so that UTF-8 conversion from [Char] to [CodePoint] is (>>= decode utf8) . encode char :: [Char] -> Maybe [CodePoint] I am sure many complexities of character encodings are not considered here, but that is in part the point: I would like to see Char in the language standard dissociated from Unicode and return to the more abstract concept of an information unit. -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig http://www.ethnologue.com/
Ken Shan <ken@digitas.harvard.edu> writes:
I suggest that the following Haskell types be used for the five items above:
1. Word8 2. CChar 3. CodePoint 4. Word16 5. Char
On most machines, Char will be a wrapper around Word8. (This contradicts the present language standard.)
Can you point out any machine where this is not the case? One with a Haskell implementation, or likely to have one in the future? If not, I don't see much point, and agree with Ashley to restrict "real" IO to [Word8]. I like the Encoding data structure, though.
data Encoding text code = Encoding { encode :: [text] -> Maybe [code] , decode :: [code] -> Maybe [text] }
utf8 :: Encoding CodePoint Word8 iso88591 :: Encoding CodePoint Word8
Perhaps changing it to data Encoding text code = Encoding { encode :: text -> Maybe code, ...} so that utf8 :: Encoding String [Word8] but more importantly jpeg :: Encoding Image [Word8] Perhaps [Word8], if it is the basis for IO, should be the target for *all* Encodings? And encoding, can it really fail? How about: data Encoding text -- or rather, 'data_item' or something? = Encoding {encode :: text -> [Word8], decode :: [Word8] -> Maybe text} ? -kzm -- If I haven't seen further, it is by standing in the footprints of giants
participants (2)
-
Ken Shan -
ketil@ii.uib.no