
Thanks for the comments. I think your solution misses one point in my original example... I wrote:
data ColDesc rowv = forall a. ColDesc (rowv -> a) ([a] -> a) (a -> String)
calculate :: [rowv] -> ColDesc rowv -> ([String],String) calculate rs (ColDesc valf sumf fmtf) = let vals = map valf rs in (map fmtf vals, (fmtf.sumf) vals)
This code only does the (rowv -> a) evaluation once, whereas olegs version:
calculate :: [rowv] -> ColDesc rowv -> ([String],String) calculate rs (ColDesc fmtf sumf) = (map fmtf rs, sumf rs)
does the evaluation (rowv -> a) for each element twice, I think. In a real system, as opposed to my toy example, this computation is expensive, and I don't want to do it more that necessary. Tim

Tim Docker wrote:
data ColDesc rowv = forall a. ColDesc (rowv -> a) ([a] -> a) (a -> String)
calculate :: [rowv] -> ColDesc rowv -> ([String],String) calculate rs (ColDesc valf sumf fmtf) = let vals = map valf rs in (map fmtf vals, (fmtf.sumf) vals)
This code only does the (rowv -> a) evaluation once
Sorry I didn't know of that requirement. The desired sharing can easily be introduced:
data Results = Results { formatted:: [String], aggregated:: String }
type ColDesc rowv = [rowv] -> Results
calculate :: [rowv] -> ColDesc rowv -> ([String],String) calculate rs transformer = (formatted res, aggregated res) where res = transformer rs
rows = ["I","wish","to","define","a","report"]
mapp g f = g . (map f)
cols = [ \rvs -> Results rvs "", \rvs -> let vals = map length rvs in Results (map show vals) (show$sum vals), \rvs -> let vals = map (\s -> length s * length s) rvs in Results (map show vals) (show$maximum vals) ]
values = [ calculate rows col | col <- cols ]
If we just need to format one value, we can write
format_value v transformer = formatted $ transformer [v]
Due to laziness, the aggregate function will not be computed, unless specifically requested.
participants (2)
-
oleg@pobox.com
-
Tim Docker