[Haskell-beginners] A better way?

Patrick LeBoutillier patrick.leboutillier at gmail.com
Sat Feb 21 17:54:46 EST 2009


Hi,

I came up with this, which seems to work well if all your rows have
the same number of fields:

maxRowFieldWidths :: [[String]] -> [Int]
maxRowFieldWidths rows = foldr rowMax zeros rows
  where rowMax fields maxes = zipWith (\f m -> max (length f) m) fields maxes
        zeros = 0 : zeros

foldr is the key here, which allows you to "accumulate" the results of
computations. In this case the accumulator is the list of all the
maximums found so far. The initial value for the accumulator is an
(infinite) list made up on only zeros. Haskell will generate only as
much as it needs.


Patrick



On Sat, Feb 21, 2009 at 4:35 PM, Keith Sheppard <keithshep at gmail.com> wrote:
> Hello,
>
> I'm new to haskell and still getting used to working with lazy
> evaluation. I created a little function to calculate column widths for
> a 2D list of strings (a table) by iterating through the list and
> accumulating a max value for each column. My initial implementation
> ran out memory for tables with many rows because of lazy evaluation
> and here is how I dealt with it:
>
> {- |
> for a table, calculate the max width in characters for each column
> -}
> maxTableColumnWidths :: [[String]] -> [Int]
> maxTableColumnWidths [] = []
> maxTableColumnWidths table =
>    maxTableColumnWidthsInternal table []
>
> maxTableColumnWidthsInternal :: [[String]] -> [Int] -> [Int]
> maxTableColumnWidthsInternal [] prevMaxValues = prevMaxValues
> maxTableColumnWidthsInternal (row:tableTail) prevMaxValues
>    | seqList prevMaxValues = undefined
>    | otherwise = maxTableColumnWidthsInternal tableTail
> (maxRowFieldWidths row prevMaxValues)
>
> -- this little function is for making the list strict... otherwise
> -- we run out of memory
> seqList [] = False
> seqList (head:tail)
>    | head `seq` False = undefined
>    | otherwise = seqList tail
>
> maxRowFieldWidths :: [String] -> [Int] -> [Int]
> maxRowFieldWidths row prevMaxValues =
>    let colLengths = map length row
>        lengthOfRow = length row
>        lengthOfPrevMax = length prevMaxValues
>        maxPrefixList = zipWith max colLengths prevMaxValues
>    in
>        if lengthOfRow == lengthOfPrevMax then
>            maxPrefixList
>        else if lengthOfRow > lengthOfPrevMax then
>            maxPrefixList ++ (drop lengthOfPrevMax colLengths)
>        else
>            maxPrefixList ++ (drop lengthOfRow prevMaxValues)
>
>
> This works but it isn't very pretty (maybe also inefficient?). Is
> there a better way to deal with this kind of memory issue?
>
> Thanks!
> Keith
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>



-- 
=====================
Patrick LeBoutillier
Rosemère, Québec, Canada


More information about the Beginners mailing list