Simon,

Since you've been re-implementing the balance report in Haskell, I thought I'd share with you in pseudocode how I rewrote it for Ledger 3.0, since the old method never stopped with the bugs. The new scheme uses a 5 stage algorithm, with each stage gathering information for the next:

STEP 1

Based on the user's query, walk through all the transactions in their journal, finding which ones to include in the account subtotals. For each transaction that matches, mark the account as VISITED.

STEP 2

Recursively walk the accounts tree, depth-first, computing aggregate totals and aggregate "counts" (number of transactions contributing to the aggregate total).

STEP 3

Walk the account tree again, breadth-first, and for every VISITED account, check whether it matches the user's "display predicate". If so, mark the account as MATCHING.

STEP 4

Do an in-order traversal of the account tree. Except for the top-most account (which serves strictly as a container for the other accounts):

 a. If the account was MATCHING, or two or more of its children are
    MATCHING or had descendents who were MATCHING, display the account.

 b. Otherwise, if the account had *any* children or descendants who
    were VISITED and *no* children or descendants who were MATCHING,
    then apply the display predicate from STEP 3 to the account.  If
    it matches, also print this account.  (This step allows -E to
    report empty accounts which otherwise did match the original
    query).

STEP 5

When printing an account, display a "depth spacer" followed by the "partial name".

The partial name is found by taking the base account's name, then prepending to it every non-MATCHING parent until a MATCHING parent is found.

The depth spacer is found by outputting two spaces for every MATCHING parent.

This way, "Assets:Bank:Checking" might be reported as:

  Assets
    Bank
      Checking

or

  Assets
    Bank:Checking

or

  Assets:Bank:Checking

Depending on whether the parents were or were not reported for their own reasons.

John

Reply via email to