> module Project3D(table) > where > import SequenceUtilities(transpose, reps) > import IOutilities(leftJustify, spaces) table builds a sequence of rows from a sequence of columns each column is a sequence of strings all columns have the same number of elements in them all rows delivered have the same number of characters in them if m(i) is the length of the longest string in column i and there are c columns, then the k-th row is the concatenation of c strings, the i-th one of which is a padded version of the k-th element of the i-th column, where the padding consists of enough spaces to make the padded version m(i)+g characters long, where g is the gap between columns, except that the last element of each row is padded to be m(c) characters long Examples: table 3 [["Char", "String", "Bool"], ["Int", "Integer", "Rational"], ["Float", "Complex Float", "Double"]] = ["Char Int Float ", "String Integer Complex Float", "Bool Rational Double "] table 1 [["Char", "String", "Bool"], ["Int", "Integer", "Rational"], ["Float", "Complex Float", "Double"]] = ["Char Int Float ", "String Integer Complex Float", "Bool Rational Double "] table 0 [["Char", "String", "Bool"], ["Int", "Integer", "Rational"], ["Float", "Complex Float", "Double"]] = ["Char Int Float ", "StringInteger Complex Float", "Bool RationalDouble "] table 1 [ ] = [ ] > table :: Int -> [[String]] -> [String] > table gapWidth columns = > [concat row | row <- transpose paddedColumns] > where > paddedColumns = > zipWith uniformLengths columnWidthsWithGaps columns > gaps = reps (max 0 (length columns - 1)) gapWidth ++ [0] > columnWidthsWithGaps = zipWith (+) columnWidths gaps > columnWidths = [maximum[length w | w <- c] | c <- columns] regularize lengths of all words in a sequence > uniformLengths :: Int -> [String] -> [String] > uniformLengths n ws = [leftJustify n w | w <- ws] A property of table: All the rows of a table are the same length. That is, if g::Int, g >= 0, cs::[[String]], and r and s are any two elements of table g cs, then length(r) = length(s). proof: Suppose col is an element of the sequence paddedColumns in the definition of table. Then col = uniformLengths w c = [leftJustify w s | s <- c] where w and c are corresponding elements of columnWidthsWithGaps and columns, columnWidthsWithGaps = zipWith (+) columnWidths gaps, and gaps = reps (max 0 (length columns - 1) g ++ [0] Observe that each element of gaps is non-negative because it is either g (non-negative by assumption) or zero. Therefore, each element of columnWidthsWithGaps, being a sum of the corresponding element of columnWidths and a non-negative number, is at least as large as the corresponding element of columnWidths. By definition, columnWidths = [maximum[length s | s <- c] | c <- cs] Therefore, if mi is the i-th entry in columnWidths, then no string in column ci is longer than mi. It is a property of leftJustify that the length of the string it delivers is equal to its first argument as long as the length of the string supplied as its second argument does not exceed its first argument. Therefore, the length of every string in col is w. That is, all the strings in col have the same length. Let r = [c1, c2, ..., cn] be an element of transpose paddedColumns. A property of the transpose function then implies that cj must be an element of the j-th sequence in paddedColumns. All of the elements in that sequence are strings of the same length. Call that length wj. That is length cj = wj According to the definition of the function table, the row in the table corresponding to the element r is row = concat r = c1 ++ c2 ++ c3 ++ ... ++ cn So, by Theorem D-length, length(row) = w1 + w2 + w2 + ... + wn. This length doesn't depend on which row was selected, so all rows must be this same length. QED Testing > column1 = ["Char", "String", "Bool"] > column2 = ["Int", "Integer", "Rational"] > column3 = ["Float", "Complex Float", "Double"] > columns = [column1, column2, column3] > t1 = table 3 columns > t2 = table 1 columns > t3 = table 0 columns > t4 = table 1 [ ]