[racket] Help needed representing data | 2d hashes?

From: Horace Dynamite (horace.dynamite at gmail.com)
Date: Wed Aug 11 16:59:08 EDT 2010

I'm trying to implement a specification which has defined three
character tables.
These character tables together implement the ASCII character set, and
further, some special characters defined by the specification.

I've copied this table here: http://en.wikipedia.org/wiki/User:Horaced

The character sets A, B, C are changed between during the parse of a
string which is ultimately encoded into those ones and noughts you see
in the table. I've managed to represent the three characters sets (A,
B and C) and mappings to the encoding strings (via three hashes, which
feels non-schemly). The information I can't fit into my data
representation however is the values column in the table above. This
will be clearer with my code below (sorry about verbosity).

;; Please ignore, just provided so you can run this code.
(define FNC1   (integer->char #xf1))
(define FNC2   (integer->char #xf2))
(define FNC3   (integer->char #xf3))
(define FNC4   (integer->char #xf4))
(define SHIFT  (integer->char #xf5))
(define CODEA  (integer->char #xf6))
(define CODEB  (integer->char #xf7))
(define CODEC  (integer->char #xf8))
(define STARTA (integer->char #xf9))
(define STARTB (integer->char #xfa))
(define STARTC (integer->char #xfb))
(define STOP   (integer->char #xfc))

;; These are the values ordered as in the encoding column in the table above.
(define ENCODING
  (list 11011001100 11001101100 11001100110 10010011000
        10010001100 10001001100 10011001000 10011000100
        10001100100 11001001000 11001000100 11000100100
        10110011100 10011011100 10011001110 10111001100
        10011101100 10011100110 11001110010 11001011100
        11001001110 11011100100 11001110100 11101101110
        11101001100 11100101100 11100100110 11101100100
        11100110100 11100110010 11011011000 11011000110
        11000110110 10100011000 10001011000 10001000110
        10110001000 10001101000 10001100010 11010001000
        11000101000 11000100010 10110111000 10110001110
        10001101110 10111011000 10111000110 10001110110
        11101110110 11010001110 11000101110 11011101000
        11011100010 11011101110 11101011000 11101000110
        11100010110 11101101000 11101100010 11100011010
        11101111010 11001000010 11110001010 10100110000
        10100001100 10010110000 10010000110 10000101100
        10000100110 10110010000 10110000100 10011010000
        10011000010 10000110100 10000110010 11000010010
        11001010000 11110111010 11000010100 10001111010
        10100111100 10010111100 10010011110 10111100100
        10011110100 10011110010 11110100100 11110010100
        11110010010 11011011110 11011110110 11110110110
        10101111000 10100011110 10001011110 10111101000
        10111100010 11110101000 11110100010 10111011110
        10111101110 11101011110 11110101110 11010000100
        11010010000 11010011100 1100011101011))

;; The following three definitions define the three character sets, A,
B and C. There is some
;; machinery to shuffle the values into their respective ASCII
positions where appropriate (please ignore).
;; The list of funny names are unique to the specification, please also ignore.
(define 128-A
  (append
   (map integer->char (build-list 64 (λ (c) (+ 32 c))))
   (map integer->char (build-list 32 (λ (c) c)))
   (list FNC3 FNC2 SHIFT CODEC CODEB FNC4 FNC1 STARTA STARTB STARTC STOP)))

(define 128-B
  (append
   (map integer->char (build-list 64 (λ (c) (+ 32 c))))
   (map integer->char (build-list 32 (λ (c) (+ 97 c))))
   (list FNC3 FNC2 SHIFT CODEC FNC4 CODEA FNC1 STARTA STARTB STARTC STOP)))

(define 128-C
  (append
   (build-list 100 values)
   (list CODEB CODEA FNC1 STARTA STARTB STARTC STOP)))

(define A
  (make-hash (build-list 107 (λ (n) (cons (list-ref 128-A n)
                                          (list-ref ENCODING n))))))
(define B
  (make-hash (build-list 107 (λ (n) (cons (list-ref 128-B n)
                                          (list-ref ENCODING n))))))
(define C
  (make-hash (build-list 107 (λ (n) (cons (list-ref 128-C n)
                                          (list-ref ENCODING n))))))

I made these hashes so that I can ask, given that I'm in character set
A, what is the encoding of the character G? And Racket would respond,
11010001000. I'd also like to say, independent of my character set,
what is the value of character G? And racket would respond 39. Kindly
note, by "value" I'm referring to the "value" column in the above
linked table, not its meaning to the interpreter.

I've rushed my explanations here so as not to overwhelm prospective
readers. I hope I haven't done this, but if what I've said seems
cryptic, given that the code has now been presented I may better
explain my problem if needed.

I'm tying to port some Perl code I found, maybe someone who knows Perl
can show me how to use hashes like this program has done,

# This is doing the same as my 128-* definitions above, same machinery.
%CODE_CHARS = ( A => [ (map { chr($_) } 040..0137, 000..037),
                       FNC3, FNC2, Shift, CodeC, CodeB, FNC4, FNC1,
                       StartA, StartB, StartC, Stop ],
                B => [ (map { chr($_) } 040..0177),
                       FNC3, FNC2, Shift, CodeC, FNC4, CodeA, FNC1,
                       StartA, StartB, StartC, Stop ],
                C => [ ("00".."99"),
                       CodeB, CodeA, FNC1, StartA, StartB, StartC, Stop ]);

# And now the the thing I can't figure out how to do, the programmer
creates a 2d hash, retaining the "values" column.
%CODE = ( A => { map { $CODE_CHARS{A}[$_] => $_ } 0..106 },
          B => { map { $CODE_CHARS{B}[$_] => $_ } 0..106 },
          C => { map { $CODE_CHARS{C}[$_] => $_ } 0..106 } );

Golly, I'm sorry for this long post.

Thanks so much for reading,
Horace.


Posted on the users mailing list.