(* Code that differs from how it appears in the book are marked "revised" or "new." *) datatype huffTree = Leaf of char * int | Internal of huffTree * huffTree * string * int; fun freq(Leaf(sym, f)) = f | freq(Internal(left, right, sym, f)) = f; fun symbols(Leaf(sym, f)) = str(sym) | symbols(Internal(left, right, sym, f)) = sym; fun makeTree(left, right) = Internal(left, right, symbols(left) ^ symbols(right), freq(left) + freq(right)); fun printTree(Leaf(sym, f)) = print("Leaf(\"" ^ str(sym) ^ "\", " ^ Int.toString(f) ^ ")") | printTree(Internal(left, right, syms, f)) = (print("makeTree("); printTree(left); print(", "); printTree(right); print(")")); fun addCharToFreqList(c, []) = [(c, 1)] | addCharToFreqList(c, (x, f)::rest) = if c = x then (x,f+1)::rest else (x,f)::addCharToFreqList(c, rest); fun charListToFreqList([]) = [] | charListToFreqList(c::rest) = addCharToFreqList(c, charListToFreqList(rest)); fun msgToFreqList(msg) = charListToFreqList(explode(msg)); (* sample *) val namePairs = [(#"A", 4), (#"C", 1), (#"D", 1), (#"E", 2), (#"G", 1), (#"I", 1), (#"K", 1), (#"N", 5), (#"R", 2), (#"U", 1), (#"V", 1), (#" ", 2)]; (* revised *) (* For Project 6.A *) fun adjoinSet(x, []) = [x] | adjoinSet(x, fst::rest) = if freq(x) < freq(fst) then ?? else ?? fun makeLeafSet([]) = [] | makeLeafSet((sym, f)::morePairs) = adjoinSet(Leaf(sym, f), makeLeafSet(morePairs)); (* revised *) fun oneMerge(x::y::rest) = adjoinSet(makeTree(x,y), rest); (* revised *) (* For Project 6.B *) fun successiveMerge([x]) = x | successiveMerge(x::y::rest) = ?? (* new *) fun generateHuffTree(pairs) = successiveMerge(makeLeafSet(pairs)); datatype bit = One | Zero; (* new *) (* Extra utility function *) fun printBit(One) = print("One") | printBit(Zero) = print("Zero"); (* For Project 6.C *) fun encodeSymbol(sym, tree) = let fun encodeSymbol1(sy, Leaf(st, f)) = if sy = st then SOME [] else NONE | encodeSymbol1(sy, Internal(left, right, st, f)) = case (encodeSymbol1(sy, left), encodeSymbol1(sy, right)) of (NONE, NONE) => ?? | (NONE, SOME bits) => ?? | (SOME bits, x) => ?? in valOf(encodeSymbol1(sym,tree)) end; fun encodeList([], tree) = [] | encodeList(fst::rest, tree) = encodeSymbol(fst, tree)@encodeList(rest, tree); fun encode(msg, tree) = encodeList(explode(msg), tree); (* For Project 6.D *) fun chooseBranch(Zero, Internal(left, right, s, f)) = left | chooseBranch(One, Internal(left, right, s, f)) = right; fun decode(bits, tree) = let fun decode1([], currentBranch) = [] | decode1(b::rest, currentBranch) = let val nextBranch = chooseBranch(b, currentBranch) in case nextBranch of Leaf(sym, w) => ?? | Internal(left, right, syms, w) => ?? end; in implode(decode1(bits, tree)) end; (* new *) (* Not mentioned in the text, but is a convenient way to generate an encoded message and key from a text. *) fun encodeAll(msg) = let val nameTree = generateHuffTree(msgToFreqList(msg)) in (encode(msg, nameTree), nameTree) end;