Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: some text on Explainable codebase #5

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/current_system/codebase/explainable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Explainable

## Types

```haskell
type ExplainableIO r st a = RWST (HistoryPath,r) [String] st IO (a,XP)
type Explainable r st a = ExplainableIO r st a
```

## Evaluation

TODO
118 changes: 118 additions & 0 deletions docs/current_system/codebase/generic_mathlang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Generic MathLang

Generic MathLang is meant to be an intermediate step between the [Rule datatype](./rule_ast.md) and [MathLang](./mathlang.md).

Things that get more structured from Rule. A lot of things in Rule are just free text inside a `MTExpr`, but it gets parsed in Generic MathLang.

### Arithmetic expressions

In Rule, a single cell may contain arbitrary expressions. Compare lines 1 and 2:

```
SUM,foo,bar,,,,,,, (1)
,,,,,,,,,
foo + bar,,,,,,,,, (2)
```

Version (1) is parsed as an arithmetic expression in Rule, but version (2) is just free text. Generic MathLang parses everything it can, even inside the cells.

### Records

Text like `foo's,bar's,baz` gets parsed into records: `foo.bar.baz`.

### Functions

Rule may define functions as follows (see [example spreadsheet](https://docs.google.com/spreadsheets/d/1cWAb7Ba4HJovQn1PquZzYJjnjKUuhEPhNHzAH4ZfV4I/edit#gid=2100528279) for larger context):


```
GIVEN x IS A Number
y IS A Number
DECIDE x discounted by y IS x * (1 - y)
```

And we can apply the function (simplified the arguments):
```
DECIDE Answer IS firstArg discounted by secondArg
```

When parsed into rules, we don't have much structure:



```haskell
HC { hHead = RPConstraint
[ MTT "x", MTT "discounted by", MTT "y" ] RPis
[ MTT "x * (1 - y)" ]
, hBody = Nothing}

HC { hHead = RPConstraint
[ MTT "Answer" ] RPis
[ MTT "firstArg"
, MTT "discounted by"
, MTT "secondArg" ]
, hBody = Nothing}
```

The definition becomes as follows:

```haskell
( "discounted by",
(
[ MkVar "x", MkVar "y" ], MkExp
{ exp = ENumOp
{ numOp = OpMul, nopLeft = MkExp
{ exp = EVar
{ var = MkVar "x" }, md = [{- omitted some metadata: line number, type etc. -}]
}, nopRight = MkExp
{ exp = ENumOp
{ numOp = OpMinus, nopLeft = MkExp
{ exp = ELit
{ lit = EInteger 1 }, md = [{- omitted some metadata -}]
}, nopRight = MkExp
{ exp = EVar
{ var = MkVar "y" }, md = [{- omitted some metadata -}]
}
}, md = [{- omitted some metadata -}]
}
}, md = [{- omitted some metadata -}]
}
)
)
```

And the application as follows:

```haskell
EVarSet
{ vsetVar = MkExp
{ exp = EVar { var = MkVar "Answer" }, md = [] }, arg = MkExp
{ exp = EApp
{ func = MkExp
{ exp = EApp
{ func = MkExp
{ exp = EVar
{ var = MkVar "discounted by" }, md = [{- omitted some metadata -}]
}, appArg = MkExp
{ exp = EVar
{ var = MkVar "Step 3" }, md = [{- omitted some metadata -}]
}, md = []
}, appArg = MkExp
{ exp = ERec
{ fieldName = MkExp
{ exp = EVar
{ var = MkVar "risk cap" }, md = [{- omitted some metadata -}]
}, recName = MkExp
{ exp = EVar
{ var = MkVar "accident" }, md = [{- omitted some metadata -}]
}
}, md = []
}
}, md = []
}
}
```

## Types

[](https:/smucclaw/dsl/blob/main/lib/haskell/natural4/src/LS/XPile/MathLang/GenericMathLang/GenericMathLangAST.hs)
7 changes: 5 additions & 2 deletions docs/current_system/codebase/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ TODO

## [The 'Explainable' codebase](https:/smucclaw/dsl/tree/main/lib/haskell/explainable)

[TODO]
The Explainable codebase includes the following components.

- [MathLang](./mathlang.md): a DSL for arithmetic expressions and predicates
- [Explainable](./explainable.md): a monad for evaluating MathLang expressions and providing explanations for the (intermediate and final) results

## Visualizations

### [Ladder Diagram](https:/smucclaw/ladder-diagram)

* [The main Ladder Diagram repo](https:/smucclaw/ladder-diagram)
* There are also docs available for this, via
* There are also docs available for this, via
```
npm install jsdoc -g
npm run docs
Expand Down
70 changes: 70 additions & 0 deletions docs/current_system/codebase/mathlang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# MathLang

Hornlikes from [Rule](./rule_ast.md) can be transformed into MathLang expressions. AFAIK there's no attempt to transform other rule types (regulative, constitutive, …).

## Types

The core of MathLang is the following `Expr` type (reordered here, but all constructors are shown).

```haskell
type ExprLabel = Maybe String
data Expr a =
-- I think these are the most relevant constructors
Val ExprLabel a -- ^ simple value
| MathBin ExprLabel MathBinOp (Expr a) (Expr a) -- ^ binary arithmetic operation
| MathVar String -- ^ variable reference
| MathSet String (Expr a) -- ^ variable assignment
| MathITE ExprLabel (Pred a) (Expr a) (Expr a) -- ^ if-then-else
| ListFold ExprLabel SomeFold (ExprList a) -- ^ fold a list of expressions into a single expr value

-- These I find less important / could probably be restructured?
| Parens ExprLabel (Expr a) -- ^ parentheses for grouping (??? why is this needed)
| MathMax ExprLabel (Expr a) (Expr a) -- ^ max of two expressions (ListFold covers this)
| MathMin ExprLabel (Expr a) (Expr a) -- ^ min of two expressions "
| MathApp ExprLabel String [String] (Expr a) -- ^ kind of a hack to allow for function to call another function etc. This constructor is removed in final result and the functions are inlined.
| Undefined ExprLabel -- ^ looks like a quick workaround after realizing there should be a way to recover from failure?

```

There's also similar structure for predicates.

```haskell
-- | conditional predicates: things that evaluate to a boolean
data Pred a
= PredVal ExprLabel Bool
| PredNot ExprLabel (Pred a) -- ^ boolean not
| PredComp ExprLabel Comp (Expr a) (Expr a) -- ^ Ord comparisions: x < y
| PredBin ExprLabel PredBinOp (Pred a) (Pred a) -- ^ predicate and / or / eq / ne
| PredVar String -- ^ boolean variable retrieval
| PredSet String (Pred a) -- ^ boolean variable assignment
| PredITE ExprLabel (Pred a) (Pred a) (Pred a) -- ^ if then else, booleans
| PredFold ExprLabel AndOr (PredList a) -- ^ and / or a list
```

Both expressions and predicates have list versions. PredList is just a type alias, ExprList has constructors for maps, filters etc. There's `MathSection` for partially applying binary functions, for the purpose of mapping over `ExprList`.

```haskell
type PredList a = [Pred a]

-- | We can filter, map, and mapIf over lists of expressions. Here, @a@ is pretty much always a @Double@.
data ExprList a
= MathList ExprLabel [Expr a] -- ^ a basic list of `Expr` expressions
| ListMap ExprLabel (MathSection a) (ExprList a) -- ^ apply the function to everything
| ListFilt ExprLabel (Expr a) Comp (ExprList a) -- ^ eliminate the unwanted elements
| ListMapIf ExprLabel (MathSection a) (Expr a) Comp (ExprList a) -- ^ leaving the unwanted elements unchanged
| ListConcat ExprLabel [ExprList a] -- ^ [[a]] -> [a]
| ListITE ExprLabel (Pred a) (ExprList a) (ExprList a) -- ^ if-then-else for expr lists

data MathSection a
= Id
| MathSection MathBinOp (Expr a)

data MathBinOp = Plus | Minus | Times | Divide | Modulo
```

## Pipeline

1. Spreadsheet gets parsed into a Rule
2. Rule (only Hornlike) gets transformed into [Generic MathLang](./generic_mathlang.md)
3. Generic MathLang is transformed into MathLang.