Headline

Logging in Haskell with non-monadic code

Characteristics

Starting from a straightforward family of functions for cutting salaries, the concern of logging the salary changes is incorporated into the functions such that the function results are enriched by the log entries for salary changes. This code is relatively verbose and implies poor abstraction. In particular, functionality for composing logs is scattered all over the functions. Ultimately, such a problem must be addressed with monads.

Illustration

Salary changes can be tracked in logs as follows:

type Log = [LogEntry]

data LogEntry = 
     LogEntry {
       name :: String, 
       oldSalary :: Float,
       newSalary :: Float 
     }
  deriving (Show)

Here are a few entries resulting from a salary cut for the sample company:

[LogEntry {name = "Craig", oldSalary = 123456.0, newSalary = 61728.0},
 LogEntry {name = "Erik", oldSalary = 12345.0, newSalary = 6172.5},
 LogEntry {name = "Ralf", oldSalary = 1234.0, newSalary = 617.0},
 LogEntry {name = "Ray", oldSalary = 234567.0, newSalary = 117283.5},
 LogEntry {name = "Klaus", oldSalary = 23456.0, newSalary = 11728.0},
 LogEntry {name = "Karl", oldSalary = 2345.0, newSalary = 1172.5},
 LogEntry {name = "Joe", oldSalary = 2344.0, newSalary = 1172.0}]

Given a log, the median of salary deltas can be computed as follows:

log2median :: Log -> Float
log2median = median . log2deltas

log2deltas :: Log -> [Float]
log2deltas = sort . map delta
  where
    delta entry = newSalary entry - oldSalary entry

The above log reduces to the following median:

-6172.5

Feature:Cut is implemented in logging-enabled fashion as follows:

cut :: Company -> (Company, Log)
cut (Company n ds) = (Company n ds', log)
  where
   (ds', logs) = unzip (map cutD ds)
   log = concat logs
   cutD :: Department -> (Department, Log)
   cutD (Department n m ds es)
     = (Department n m' ds' es', log)
     where
       (m',log1) = cutE m
       (ds', logs2) = unzip (map cutD ds)
       (es', logs3) = unzip (map cutE es)
       log = concat ([log1]++logs2++logs3)
       cutE :: Employee -> (Employee, Log)
       cutE (Employee n a s) = (e', log)
         where
           e' = Employee n a s'
           s' = s/2
           log = [ LogEntry { 
                     name = n,
                     oldSalary = s,
                     newSalary = s'
                 } ]

Thus, all functions return a regular data item (i.e., some part of the company) and a corresponding log. When lists of company parts are processed with map, then the lists of results must be unzipped (to go from a list of pairs to a pair of lists). In the function for departments, multiple logs arise for parts a department; these intermediate logs must be composed.

Relationships

  • See Contribution:haskellComposition for the corresponding contribution that does not yet involve logging. The data model is preserved in the present contribution, but the functions for cutting salaries had to be rewritten since the logging concern crosscuts the function.
  • See Contribution:haskellWriter for a variation on the present contribution, which leverages a writer monad, though, for conciseness and proper abstraction.

Architecture

There are these Haskell modules:

The contribution relies on the hackage package hstats.


Ralf Lämmel edited this article at Sat, 20 Jun 2020 18:45:30 +0200
Compare revisions Compare revisions

User contributions

    This user never has never made submissions.

    User edits

    Syntax for editing wiki

    For you are available next options:

    will make text bold.

    will make text italic.

    will make text underlined.

    will make text striked.

    will allow you to paste code headline into the page.

    will allow you to link into the page.

    will allow you to paste code with syntax highlight into the page. You will need to define used programming language.

    will allow you to paste image into the page.

    is list with bullets.

    is list with numbers.

    will allow your to insert slideshare presentation into the page. You need to copy link to presentation and insert it as parameter in this tag.

    will allow your to insert youtube video into the page. You need to copy link to youtube page with video and insert it as parameter in this tag.

    will allow your to insert code snippets from @worker.

    Syntax for editing wiki

    For you are available next options:

    will make text bold.

    will make text italic.

    will make text underlined.

    will make text striked.

    will allow you to paste code headline into the page.

    will allow you to link into the page.

    will allow you to paste code with syntax highlight into the page. You will need to define used programming language.

    will allow you to paste image into the page.

    is list with bullets.

    is list with numbers.

    will allow your to insert slideshare presentation into the page. You need to copy link to presentation and insert it as parameter in this tag.

    will allow your to insert youtube video into the page. You need to copy link to youtube page with video and insert it as parameter in this tag.

    will allow your to insert code snippets from @worker.