This commit is contained in:
Samae 2023-12-02 17:38:53 +02:00
commit c01a1f9ca4
7 changed files with 208 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.cabal

78
Main.hs Normal file
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1,7 @@
dependencies:
- base == 4.*
- attoparsec
- text
executables:
interview-in:
main: Main.hs