
Hello, I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads. I want to also produce a report describing the details of this calculation for each particular set of inputs. e.g. Number of hours worked = 100. Gross pay per hour = 50. Total gross = 100 * 50 = 500. etc. But about 20 times more complicated than the above. Naturally I need to write functions to produce the above description/report as it should be well presented. Only showing the important parts of the calculation in a sensible order. But I am wondering how to combine the generation of the report with the calculation together. I think if I add the report generating functions into the calculation functions, it will make them twice as messy, and they are already complicated enough. On the other hand replicating the calculation source code twice, once without reporting and once without seems bad. Any suggestions on how to handle this? Rene.

On Wed, 15 Jun 2005, Rene de Visser wrote:
Hello,
I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads.
I want to also produce a report describing the details of this calculation for each particular set of inputs. e.g. Number of hours worked = 100. Gross pay per hour = 50. Total gross = 100 * 50 = 500.
Is this example computed with Excel? :-]
I think if I add the report generating functions into the calculation functions, it will make them twice as messy, and they are already complicated enough.
On the other hand replicating the calculation source code twice, once without reporting and once without seems bad.
I think that it is good style to separate computations from input/output operations and formatting. I suggest to divide the calculatoin into smaller parts. If you have more breaks you have more chances to get temporary results. You can put temporary values into a data structure. E.g. if you have an iteration don't write a recursion with a fixed abort criterion but write a function which maps the old value to the new one, then apply 'iterate' on it. Now you can inspect the temporary values and you can later apply a function which decides when to stop the iteration.

From: Henning Thielemann
On Wed, 15 Jun 2005, Rene de Visser wrote: I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads. I want to also produce a report describing the details of this calculation for each particular set of inputs. On the other hand replicating the calculation source code twice, once without reporting and once without seems bad.
smaller parts. If you have more breaks you have more chances to get temporary results. You can put temporary values into a data structure. E.g. if you have an iteration don't write a recursion with a fixed abort criterion but write a function which maps the old value to the new one, then apply 'iterate' on it. Now you can inspect the temporary values and you can later apply a function which decides when to stop the iteration.
Thankyou for the reply, The calculation is for the mostly already structured as you have suggested. The trouble is there are lots of little pieces that need to be put together. Do I need to put these pieces together twice? Once to put the whole calculation together? And once to do the reporting? This is what I'd like to avoid. (A good deal of the complexity comes from that the calculation has a complex structure). It would be nice to describe the structure once (at the moment the structure of the calculation is describe impliciitly in the Haskell functions) and use it both for the calculation and for the reporting. I thought about using some like Buddha or Hat to generate a data structure describing the calculation and mining this for the reporting. But these seems like horrible over kill, and probably not very change resistant, not to mention making the development not very interactive. Rene.

At 18:48 15/06/05 +0200, Rene de Visser wrote:
From: Henning Thielemann
On Wed, 15 Jun 2005, Rene de Visser wrote: I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads. I want to also produce a report describing the details of this calculation for each particular set of inputs. On the other hand replicating the calculation source code twice, once without reporting and once without seems bad.
smaller parts. If you have more breaks you have more chances to get temporary results. You can put temporary values into a data structure. E.g. if you have an iteration don't write a recursion with a fixed abort criterion but write a function which maps the old value to the new one, then apply 'iterate' on it. Now you can inspect the temporary values and you can later apply a function which decides when to stop the iteration. Thankyou for the reply, The calculation is for the mostly already structured as you have suggested. The trouble is there are lots of little pieces that need to be put together.
Do I need to put these pieces together twice? Once to put the whole calculation together? And once to do the reporting? This is what I'd like to avoid.
(A good deal of the complexity comes from that the calculation has a complex structure).
It would be nice to describe the structure once (at the moment the structure of the calculation is describe impliciitly in the Haskell functions) and use it both for the calculation and for the reporting.
I think your "instinct" that the structure of the calculation not be repeated is sound. Furthermore, I think that Haskell is well suited to avoiding such duplication. Without knowing details of your problem it is difficult to be certain how to proceed, but it seems to me that you maybe have some kind of structure (or traversal pattern) over your data that can be separated from the computation. A starting point might be to separate the traversal from the computation, and code the traversal as a higher order function (taking a parameter which is a function that performs the data specific operations). If there are many different internal data types, it might be worth considering using a type class rather than a function parameter. (Or to go the whole hog, look up the technique described in SPJ/Ralf Laemmel's Generic Haskell work -- look for "Scrap Your Boilerplate" -- but that may be more than you need.) Staying with non-monadic functions, the computation and the formatting could be handled as simple functions, where formatting returns something like a StringS value, which can be output separately, but this might require some creativity for the type of the traversal function. Another approach would be to declare your basic traversal structure type as an extended Functor that supports an fmapM function which allows a monadic function to be applied over the structure "collecting" values in some way -- this being used to collect or perform output. There's a thread about this idea starting here: http://www.mail-archive.com/haskell@haskell.org/msg12757.html Bear in mind that, with Haskell, you can design your algorithm as if it generates an intermediate data structure without necessarily having to store the entire structure in memory. So if you have a list of values, each of which you require to subject to some transformation, followed by another operation that (say) formats the list, then you could: (a) use 'map' to apply the transformation to each element, creating a new list, then (b) use something like 'concatMap show' to format and concatenate the values. Doing this, it appears you need space the intermediate list, but lazy evaluation can mean that the entire list is never required all together. In such cases, I tend to think of the intermediate list or data structure as describing a traversal sequence or pattern, rather than as a "concrete" data value. I touch briefly on some of these issues in "Learning Haskell Notes": http://www.haskell.org/tmrwiki/LearningHaskellNotes#programming-idioms #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

From: Henning Thielemann
On Wed, 15 Jun 2005, Rene de Visser wrote: You can put temporary values into a data structure. E.g. if you have an iteration don't write a recursion with a fixed abort criterion but write a function which maps the old value to the new one, then apply 'iterate' on it. Now you can inspect the temporary values and you can later apply a function which decides when to stop the iteration.
Designing the data structures to store the calculation results seems to be non-trivial, so I guess I should do this first. Then maybe the solution to the other problem will be apparent. Rene.

Rene de Visser wrote:
Designing the data structures to store the calculation results seems to be non-trivial, so I guess I should do this first.
I think that part of the problem is that when you need to be able to reference results from the inside of a calculation (or any sort of expression) you need to be able to refer to them somehow. One of the easier ways of doing this would be to bung them into some sort of data structure, alternatives would be to use a spreadsheet type abstraction that allows you to pull things out. Someone posted a reference to an interesting paper that you may be able to build on: http://citeseer.ist.psu.edu/carlsson02monads.html It's probably not going to be a trivial translation, but once you've written your calculations in this style, you should be able to get at out the intermediate values easily. At least I wrote something similar in Java a few years ago that did similar things, and it was quite a nice of abstraction to work with. I guess it's not going to matter much for you, but the problem of using some specific data structure is that it's probably going to be very closely related to the structure of the code. If you need to change the code in any non-trivial way the data structure is going to have to change and all of the code that deals with the data structure will as well. Because your report is probably going to have to change in sync with the calcs this probably isn't going to be much of a problem, but in other situations it can be a bit of a pain.
Then maybe the solution to the other problem will be apparent.
I think your main problem is that you need some way of labeling the intermediate results so you can refer to them later when you need them in the report. One you've worked out how you're going to do that, everything else should fall into place. Hope that helps! Sam

Here is an idea I slammed out. Maybe it will help you. The basic idea is to create two types -- one which supports annotations and one which ignores them. Only write your calculations once, with annotations. Uses typeclasses to ignore the annotations when you don't want them. Rene de Visser wrote:
Hello,
I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads.
I want to also produce a report describing the details of this calculation for each particular set of inputs. e.g. Number of hours worked = 100. Gross pay per hour = 50. Total gross = 100 * 50 = 500. etc. But about 20 times more complicated than the above.
Naturally I need to write functions to produce the above description/report as it should be well presented. Only showing the important parts of the calculation in a sensible order.
But I am wondering how to combine the generation of the report with the calculation together.
I think if I add the report generating functions into the calculation functions, it will make them twice as messy, and they are already complicated enough.
On the other hand replicating the calculation source code twice, once without reporting and once without seems bad.
Any suggestions on how to handle this?
Rene.
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
{-# OPTIONS -fglasgow-exts #-}
data Annotation a = TotalGrossCalc a a a | SumCalculation [a] a | SomeCalculation a | AbsCalc a | SignumCalc a deriving Show
add a different Show instance here for meaningful reporting
class (Show a,Num a,Num x) => Annotatable a x | a -> x where mkAnnotatible :: x -> a annotate :: a -> Annotation a -> a
newtype Num a => JustCalc a = JustCalc a deriving (Eq,Num) data AnnotateCalc a = AnnotateCalc a [Annotation (AnnotateCalc a)]
ignore annotations for JustCalc
instance Num a => Annotatable (JustCalc a) a where mkAnnotatible x = JustCalc x annotate x _ = x
keep hold of them for AnnotateCalc
instance Num a => Annotatable (AnnotateCalc a) a where mkAnnotatible x = AnnotateCalc x [] annotate (AnnotateCalc x messages) msg = AnnotateCalc x (msg:messages)
some boilerplate...
instance Eq a => Eq (AnnotateCalc a) where (AnnotateCalc x _ ) == (AnnotateCalc y _ ) = x == y
instance Num a => Num (AnnotateCalc a) where (AnnotateCalc x x_msg) + (AnnotateCalc y y_msg) = AnnotateCalc (x+y) (x_msg++y_msg) (AnnotateCalc x x_msg) * (AnnotateCalc y y_msg) = AnnotateCalc (x*y) (x_msg++y_msg) fromInteger x = (AnnotateCalc (fromInteger x) []) abs z@(AnnotateCalc x x_msg) = AnnotateCalc (abs x) ((AbsCalc z):x_msg) signum z@(AnnotateCalc x x_msg) = AnnotateCalc (signum x) ((SignumCalc z):x_msg)
instance Show a => Show (AnnotateCalc a) where show (AnnotateCalc x _ ) = show x
instance (Show a,Num a) => Show (JustCalc a) where show (JustCalc x) = show x
now some calculations
sumOfHours :: Annotatable a x => [a] -> a sumOfHours xs = annotate result (SumCalculation xs result) where result = sum xs
grossTotal :: Annotatable a x => a -> a -> a grossTotal hoursWorked payRate = annotate result (TotalGrossCalc hoursWorked payRate result) where result = hoursWorked * payRate
someCalculation :: Annotatable a x => [a] -> a -> a someCalculation hrs rate = annotate result (SomeCalculation result) where result = grossTotal (sumOfHours hrs) rate
printAnnotations (AnnotateCalc _ annotations) = sequence $ map (putStrLn . show) (reverse annotations)
sample :: Annotatable a x => a sample = someCalculation (map mkAnnotatible [12,34,23,31]) (mkAnnotatible 50)
main = do let sample1 = sample :: JustCalc Integer sample2 = sample :: AnnotateCalc Integer putStrLn $ show sample1 putStrLn $ show sample2 printAnnotations sample2

Rene de Visser
I have a somewhat complicated calculation programmed in Haskell. This calculation is coded without using monads.
I want to also produce a report describing the details of this calculation for each particular set of inputs. e.g. Number of hours worked = 100. Gross pay per hour = 50. Total gross = 100 * 50 = 500. etc. But about 20 times more complicated than the above.
I suggest that you consider defining an instance of Num for the type of a "calculation result annotated with details". A binary operator like + can then both perform the calculation and combine the annotations. You probably want an additional operation (outside the Num class) that adds a new annotation for the current intermediate result. This way, you may be able to reuse all or most of your calculation code for computing with and without keeping track of the report. -- Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig Mothers are the necessity of invention. --Bill Watterson
participants (6)
-
Chung-chieh Shan
-
Graham Klyne
-
Henning Thielemann
-
Rene de Visser
-
robert dockins
-
Sam Mason