AST
This commit is contained in:
commit
c01a1f9ca4
7 changed files with 208 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.cabal
|
78
Main.hs
Normal file
78
Main.hs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import Control.Applicative ((<|>),empty)
|
||||||
|
import Data.Attoparsec.Text (Parser, parseOnly, decimal, choice, option, sepBy, endOfLine, endOfInput, many1)
|
||||||
|
import qualified Data.Maybe as M
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
|
||||||
|
insuranceNetworkParser :: Parser InsuranceNetworkAST
|
||||||
|
insuranceNetworkParser = many1 line
|
||||||
|
where
|
||||||
|
-- <line> ::= <insurer-id> ":" <percent> <optional-exprs>
|
||||||
|
-- <optional-exprs> ::= "" | "if" <exprs>
|
||||||
|
line :: Parser INASTLine
|
||||||
|
line = do
|
||||||
|
id <- insurerId
|
||||||
|
": "
|
||||||
|
pc <- percent
|
||||||
|
oe <- option [] (" if " *> exprs)
|
||||||
|
endOfLine
|
||||||
|
pure $ INASTLine id pc oe
|
||||||
|
-- <exprs> ::= <expr> | <expr> "and" <exprs>
|
||||||
|
exprs :: Parser [ INASTExpr ]
|
||||||
|
exprs = expr `sepBy` " and "
|
||||||
|
-- <expr> ::= <lesser-than> | <greater-than> | <equals> | <insurer-id>
|
||||||
|
expr :: Parser INASTExpr
|
||||||
|
expr = choice [ INASTExprLt <$> lt
|
||||||
|
, INASTExprGt <$> gt
|
||||||
|
, INASTExprEq <$> eq
|
||||||
|
, INASTExprInsurerId <$> insurerId ]
|
||||||
|
-- <lesser-than> ::= "<" <integer>
|
||||||
|
lt :: Parser INASTLt
|
||||||
|
lt = "<" *> integer
|
||||||
|
-- <greater-than> ::= ">" <integer>
|
||||||
|
gt :: Parser INASTGt
|
||||||
|
gt = ">" *> integer
|
||||||
|
-- <equals> ::= "=" <integer>
|
||||||
|
eq :: Parser INASTEq
|
||||||
|
eq = "=" *> integer
|
||||||
|
-- <insurer-id> ::= "I" <integer>
|
||||||
|
insurerId :: Parser INASTInsurerId
|
||||||
|
insurerId = "I" *> integer
|
||||||
|
-- <percent> ::= <integer> "%"
|
||||||
|
percent :: Parser INASTPercent
|
||||||
|
percent = integer <* "%"
|
||||||
|
-- <integer> ::= <digit> | <non-zero-digit> <integer>
|
||||||
|
-- Overapproximation of the grammar
|
||||||
|
integer :: Parser Int
|
||||||
|
integer = decimal
|
||||||
|
|
||||||
|
type InsuranceNetworkAST = [INASTLine]
|
||||||
|
|
||||||
|
data INASTLine = INASTLine INASTInsurerId INASTPercent [INASTExpr]
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
data INASTExpr = INASTExprLt INASTLt
|
||||||
|
| INASTExprGt INASTGt
|
||||||
|
| INASTExprEq INASTEq
|
||||||
|
| INASTExprInsurerId INASTInsurerId
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
type INASTLt = Int
|
||||||
|
type INASTGt = Int
|
||||||
|
type INASTEq = Int
|
||||||
|
type INASTInsurerId = Int
|
||||||
|
type INASTPercent = Int
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
inputNetwork <- T.readFile "./input.network"
|
||||||
|
T.putStrLn "Using the following input network:"
|
||||||
|
T.putStrLn inputNetwork
|
||||||
|
T.putStrLn "Parsed AST:"
|
||||||
|
print (parseOnly insuranceNetworkParser inputNetwork)
|
||||||
|
|
||||||
|
|
56
desc.md
Normal file
56
desc.md
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# Insurance networks
|
||||||
|
|
||||||
|
The following grammar:
|
||||||
|
|
||||||
|
```
|
||||||
|
<lines> ::= <line> | <line> "\n" <lines>
|
||||||
|
<line> ::= <insurer-id> ":" <percent> <optional-exprs>
|
||||||
|
<optional-exprs> ::= "" | "if" <exprs>
|
||||||
|
<exprs> ::= <expr> | <expr> "and" <exprs>
|
||||||
|
<expr> ::= <lesser-than> | <greater-than> | <equals> | <insurer-id>
|
||||||
|
<lesser-than> ::= "<" <integer>
|
||||||
|
<greater-than> ::= ">" <integer>
|
||||||
|
<equals> ::= "=" <integer>
|
||||||
|
<insurer-id> ::= "I" <integer>
|
||||||
|
<percent> ::= <integer> "%"
|
||||||
|
<integer> ::= <digit> | <non-zero-digit> <integer>
|
||||||
|
<digit> ::= "0" | <non-zero-digit>
|
||||||
|
<non-zero-digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
|
||||||
|
```
|
||||||
|
|
||||||
|
is used to represents insurance networks.
|
||||||
|
|
||||||
|
Given a single input of type `Int`, the job of these networks is to provide, if possible, exactly 100% underwriting capital using the fewest insurers possible. Each insurer contributes their percentage only if their respective conditions are met.
|
||||||
|
|
||||||
|
Below is a simple example of such a network:
|
||||||
|
|
||||||
|
```
|
||||||
|
I1: 50%
|
||||||
|
I2: 50% if <5
|
||||||
|
I3: 40% if I1
|
||||||
|
I4: 30% if I2 and <5
|
||||||
|
I5: 10% if I3 and I4
|
||||||
|
I6: 10% if I3
|
||||||
|
```
|
||||||
|
|
||||||
|
where:
|
||||||
|
- Insurer `I1` contributes 50% unconditionally, for any input
|
||||||
|
- `I2` contributes 50% only if the input is `<5`
|
||||||
|
- `I3` contributes 40% only if `I1` contributes
|
||||||
|
- etc...
|
||||||
|
|
||||||
|
Given the above, your task is to write a small command line program that takes 2 parameters:
|
||||||
|
- the path to a file that defines a network
|
||||||
|
- an integer input to the network
|
||||||
|
|
||||||
|
and outputs a list of the fewest contributing insurers (by their integer ids).
|
||||||
|
|
||||||
|
Eg. if your program was given the above example network and:
|
||||||
|
- input `3` then it would output `[1, 2]` (representing insurers `I1` and `I2`)
|
||||||
|
- input `6` then it would output `[1, 3, 6]`
|
||||||
|
|
||||||
|
If a network is unable to collect exactly 100% for a given input then your program should output `[]`.
|
||||||
|
|
||||||
|
Please create a new private github repository named `artificial-network`, commit all your code there and once finished please invite me, `pwm`, so we can check your solution.
|
||||||
|
|
||||||
|
Good luck!
|
24
flake.lock
Normal file
24
flake.lock
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1628427351,
|
||||||
|
"narHash": "sha256-WuZUIQ07AvRw+T9wvQ3qFf8MXmKZ+ktZz9drNgWXDbs=",
|
||||||
|
"path": "/nix/store/aqinic6h77nrsrzwdsq2mxihw0kd87ml-source",
|
||||||
|
"rev": "348bc5de8bca09c624f5c4975f538684da4713d2",
|
||||||
|
"type": "path"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
36
flake.nix
Normal file
36
flake.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
# inspired by: https://serokell.io/blog/practical-nix-flakes#packaging-existing-applications
|
||||||
|
description = "A Hello World in Haskell with a dependency and a devShell";
|
||||||
|
inputs.nixpkgs.url = "nixpkgs";
|
||||||
|
outputs = { self, nixpkgs }:
|
||||||
|
let
|
||||||
|
supportedSystems = [ "x86_64-linux" "x86_64-darwin" ];
|
||||||
|
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
|
||||||
|
nixpkgsFor = forAllSystems (system: import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [ self.overlay ];
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
overlay = (final: prev: {
|
||||||
|
interview-in = final.haskellPackages.callCabal2nix "in23" ./. {};
|
||||||
|
});
|
||||||
|
packages = forAllSystems (system: {
|
||||||
|
interview-in = nixpkgsFor.${system}.interview-in;
|
||||||
|
});
|
||||||
|
defaultPackage = forAllSystems (system: self.packages.${system}.interview-in);
|
||||||
|
checks = self.packages;
|
||||||
|
devShell = forAllSystems (system: let haskellPackages = nixpkgsFor.${system}.haskellPackages;
|
||||||
|
in haskellPackages.shellFor {
|
||||||
|
packages = p: [self.packages.${system}.interview-in];
|
||||||
|
withHoogle = true;
|
||||||
|
buildInputs = with haskellPackages; [
|
||||||
|
haskell-language-server
|
||||||
|
ghcid
|
||||||
|
cabal-install
|
||||||
|
];
|
||||||
|
# Change the prompt to show that you are in a devShell
|
||||||
|
shellHook = "export PS1='\\e[1;34mdev > \\e[0m'";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
6
input.network
Normal file
6
input.network
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
I1: 50%
|
||||||
|
I2: 50% if <5
|
||||||
|
I3: 40% if I1
|
||||||
|
I4: 30% if I2 and <5
|
||||||
|
I5: 10% if I3 and I4
|
||||||
|
I6: 10% if I3
|
7
package.yaml
Normal file
7
package.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
dependencies:
|
||||||
|
- base == 4.*
|
||||||
|
- attoparsec
|
||||||
|
- text
|
||||||
|
executables:
|
||||||
|
interview-in:
|
||||||
|
main: Main.hs
|
Loading…
Reference in a new issue