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

Dice stats #105

Merged
merged 75 commits into from
Feb 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
f8e4977
Merge pull request #65 from WarwickTabletop/main
finnbar Dec 6, 2021
9165ef5
start of some DiceStats stuff
L0neGamer Dec 6, 2021
8c6b640
Merge pull request #76 from WarwickTabletop/main
finnbar Dec 16, 2021
526d802
Merge pull request #87 from WarwickTabletop/main
finnbar Dec 23, 2021
3bbb721
Merge pull request #90 from WarwickTabletop/main
finnbar Dec 26, 2021
7751bce
merging paths
L0neGamer Jan 1, 2022
1d63187
covered the basic of the distributions, going to work on the graphing…
L0neGamer Jan 3, 2022
8675355
added base file for stats
L0neGamer Jan 3, 2022
36502b5
made progress on stats, creating a graph and some stats info. need to…
L0neGamer Jan 4, 2022
f370f8d
fixed some formatting issues
L0neGamer Jan 4, 2022
c689c57
formatting again
L0neGamer Jan 4, 2022
70d9e96
cleaned up a bit
L0neGamer Jan 4, 2022
5dc105b
merge
L0neGamer Jan 4, 2022
16a8db6
implemented rerolls and keep/drop dice operations
L0neGamer Jan 5, 2022
8e28e57
filled some holes and removed some old stuff
L0neGamer Jan 5, 2022
d872e7a
minor fixes and DiceStatsBase commenting
L0neGamer Jan 5, 2022
bb29c17
more comments, and changed distribution functions so that they can er…
L0neGamer Jan 5, 2022
34b779a
more comments, and moving do's around a lot
L0neGamer Jan 5, 2022
b3c6203
letting some empty distributions be equal to a zero value
L0neGamer Jan 5, 2022
660a9a5
ormolu
L0neGamer Jan 5, 2022
93df68b
moved to library version of Distribution
L0neGamer Jan 5, 2022
a198f0c
added typing to stop repl complaining
L0neGamer Jan 5, 2022
e7cd7b6
beginning the switch over to Experiment s for Dice statistics. seemed…
L0neGamer Jan 5, 2022
20bf17f
fixed merge issue
L0neGamer Jan 5, 2022
359a301
moved more fully over to Experiments and finished that off. more comm…
L0neGamer Jan 6, 2022
088a04c
a smidge of tidying up
L0neGamer Jan 6, 2022
7ea730b
Merge branch 'main' of https://github.com/WarwickTabletop/tablebot in…
L0neGamer Jan 6, 2022
4922ee8
Merge pull request #107 from WarwickTabletop/main
finnbar Jan 6, 2022
a39119b
beginning list distributions
L0neGamer Jan 6, 2022
135d88f
made functions fully work
L0neGamer Jan 6, 2022
278157b
Merge branch 'stable' of https://github.com/WarwickTabletop/tablebot …
L0neGamer Jan 6, 2022
ba1b8cc
some tidying
L0neGamer Jan 6, 2022
b95aca8
some tidying pt2
L0neGamer Jan 6, 2022
8e142f2
added some documentation and ensured that distribution output is alwa…
L0neGamer Jan 7, 2022
1a08e27
allowed for multiple stats to be checked at the same time, and fixed …
L0neGamer Jan 7, 2022
0a70f24
ormolu
L0neGamer Jan 7, 2022
f291653
set all of the fonts in the graph to the same font to ensure readability
L0neGamer Jan 7, 2022
54d172c
adjusted Roll.md slightly
L0neGamer Jan 7, 2022
41d6c33
undoing prev commit
L0neGamer Jan 7, 2022
e31781b
adjusting spacing in graph
L0neGamer Jan 11, 2022
00e9349
making some parser changes and running into issues with no errors sho…
L0neGamer Jan 11, 2022
5cd270d
ORMOLU!
L0neGamer Jan 11, 2022
011ac00
updated distribution
L0neGamer Jan 12, 2022
c6526cf
add some comments
L0neGamer Jan 12, 2022
c5017c5
update docs
L0neGamer Jan 12, 2022
8b0498a
made a bunch of changes to how the graphs are displayed to make them …
L0neGamer Jan 12, 2022
7890b7c
Merge branch 'main' of https://github.com/WarwickTabletop/tablebot in…
L0neGamer Jan 12, 2022
f3a3053
added commented out more modern distribution
L0neGamer Jan 19, 2022
323b288
Revamped command parser
finnbar Jan 28, 2022
f0de7ea
Tiny fix for #109
finnbar Jan 28, 2022
bc16676
Fix by @L0neGamer for WithError not erroring
finnbar Jan 28, 2022
ae00234
Merge branch 'main' of https://github.com/WarwickTabletop/tablebot in…
L0neGamer Jan 31, 2022
0d605f2
Merge branch 'error-on-subcommand' of https://github.com/WarwickTable…
L0neGamer Jan 31, 2022
5e18d29
merge
L0neGamer Jan 31, 2022
d5bb87b
making parsers better for dice
L0neGamer Jan 31, 2022
8d31a24
qualified post issue
L0neGamer Jan 31, 2022
af8ac87
expanded help message
L0neGamer Jan 31, 2022
dd8fcc8
adding some useful stuff
L0neGamer Jan 31, 2022
a1c6865
clean up and making sure errors don't occur during graphing
L0neGamer Jan 31, 2022
236134b
tried to move over to an Experiment based system for range instead. n…
L0neGamer Jan 31, 2022
332c928
removed uneeded extensions
L0neGamer Feb 3, 2022
214b939
added better dice parsing, better command parsing, remvoed some old s…
L0neGamer Feb 3, 2022
b27256d
limit length of lists to 50, added a random stats function if it need…
L0neGamer Feb 3, 2022
ec63d64
mention list length limitations
L0neGamer Feb 3, 2022
292e7f5
moving some stuff around
L0neGamer Feb 3, 2022
e5f65dc
undid some work to investigate why parse errors are being weird
L0neGamer Feb 3, 2022
1b4d1e2
reverting revertion
L0neGamer Feb 3, 2022
819b950
went to old method of parsing rolling dice which seems to work better
L0neGamer Feb 3, 2022
e245b4c
limited exports from DiceParsing
L0neGamer Feb 5, 2022
08757d9
removed uneeded packages
L0neGamer Feb 5, 2022
21a95e8
spelling change
L0neGamer Feb 5, 2022
c323989
some requested changes (up to dice stats)
L0neGamer Feb 5, 2022
9d77865
more requested changes
L0neGamer Feb 5, 2022
5452122
some more explanations
L0neGamer Feb 5, 2022
5edfa20
moved some stuff around slightly
L0neGamer Feb 5, 2022
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
2 changes: 1 addition & 1 deletion app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ main :: IO ()
main = forever $ do
loadEnv
dToken <- pack <$> getEnv "DISCORD_TOKEN"
unless (encodeUtf8 dToken =~ "^[A-Za-z0-9_-]{24}[.][A-Za-z0-9_-]{6}[.][A-Za-z0-9_-]{27}$") $
unless (encodeUtf8 dToken =~ ("^[A-Za-z0-9_-]{24}[.][A-Za-z0-9_-]{6}[.][A-Za-z0-9_-]{27}$" :: String)) $
die "Invalid token format. Please check it is a bot token"
prefix <- pack . fromMaybe "!" <$> lookupEnv "PREFIX"
dbpath <- getEnv "SQLITE_FILENAME"
Expand Down
34 changes: 34 additions & 0 deletions docs/Roll.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The roll command has a staggering amount of flexibility, as well as additional f

Below are listed the current full capabilities of the bot for rolling dice and evaluation expressions. All operations (currently) result in integers or a list. A list of functions is available in the [functions section](#Functions).

You can also generate statistics of an expression. See the [Statistics](#Statistics) section for more information.

## Basic Operators

- Addition
Expand Down Expand Up @@ -62,6 +64,8 @@ As well as simple expressions, basic list expressions can be formed. You can for

As an addendum to custom dice, if a list value is bracketed then it can be used in custom dice. For example, `5d(4#4d6)` rolls five dice, whose sides are determined by rolling 4d6 4 times. Do note that laziness still applies here, meaning that the RNG cap can be very quickly reached.

Lists are limited to 50 items long currently (which is configurable).

## Functions

Here are all the functions, what they take, and what they return.
Expand All @@ -70,6 +74,8 @@ Here are all the functions, what they take, and what they return.
- abs (integer) - the absolute value of an integer
- fact (integer < 50) - the factorial of an integer
- id (integer) - the integer
- max (integer, integer) - get the maximum item between two items
- min (integer, integer) - get the minimum item between two items
- maximum (list) - get the maximum item in a list
- minimum (list) - get the minimum item in a list
- mod (two integers, second /= 0) - get the modulo of two integers
Expand All @@ -83,3 +89,31 @@ Here are all the functions, what they take, and what they return.
- reverse (list) - reverse the list
- sort (list) - sort the list in ascending order
- take (integer, list) - take the first `n` values from a list, where `n` is the integer given
- between (integer, integer) - generate a list between the two given integers (inclusive)
- concat (list, list) - concatenate two lists together

# Statistics

As well as generating values, statistics based off of expressions can be found. There is a total time limit of 10 seconds for this command, with 5 seconds given to calculations and 5 seconds given to generating the bar chart.

To get these statistics, calling the `roll` command with the `stats` subcommand will generate the requested statistics. The expression given has to return an integer.

The bot will give the mean, the standard deviation, and the top ten most common values of the distribution, as well as graphing the entire distribution.

For example, the result of calling `roll stats 2d20kh1` (roll two twenty sided dice and keep the higher die) can be seen below.

!["The results of asking for stats of 2d20kh1 (roll two twenty sided dice and keep the highest one). The ten most common rolls are 20 to 11. The mean is 13.825. The standard deviation is about 4.7. The bar chart has values on each integer from 1 to 20, with the height of each bar increasing linearly."](./resources/dicestats_2d20kh1.jpg "the result of asking for stats of 2d20kh1")

(above: The results of asking for stats of 2d20kh1 (roll two twenty sided dice and keep the highest one). The ten most common rolls are 20 to 11. The mean is 13.825. The standard deviation is about 4.7. The bar chart has values on each integer from 1 to 20, with the height of each bar increasing linearly.)

Currently, the statistics generation supports all valid expressions.

If invalid states occur (such as with division by zero, negative exponents, or infinite rerolls) the bot will alert the user only if the entire distribution becomes empty. For example, in `1d20rr<(21-d{0,1})`, half of the time infinite rerolls will occur. In this case, these invalid cases are ignored, as they can never be actually rolled, and the only value output is `20`. If the expression given is instead `1/0`, the entire distribution will be empty, as there is no valid output from this expression.

As well as statistics for a given expression, multiple expressions can be shown in the same instance.

For example, the result of calling `roll stats 2d20kh1 4d6dl1` is as follows.

!["The results of asking for stats of 2d20kh1 and 4d6dl1 (roll two twenty sided dice and keep the highest one, and roll four dice with six sides, and drop the lowest value of each). The most common rolls for each expression are 20 to 16, and 13, 12, 14, 11, and 15. The means are about 13.8 and 12.2. The standard deviation are about 4.7 and 2.8. The bar chart has blue values on each integer from 1 to 20, with the height of each bar increasing linearly, and green values that form a weighted bell curve centered on 13."](./resources/dicestats_2d20kh1_4d6dl1.jpg "the result of asking for stats of 2d20kh1 and 4d6dl1")

(above: The results of asking for stats of 2d20kh1 and 4d6dl1 (roll two twenty sided dice and keep the highest one, and roll four dice with six sides, and drop the lowest value of each). The most common rolls for each expression are 20 to 16, and 13, 12, 14, 11, and 15. The means are about 13.8 and 12.2. The standard deviation are about 4.7 and 2.8. The bar chart has blue values on each integer from 1 to 20, with the height of each bar increasing linearly, and green values that form a weighted bell curve centered on 13.)
Binary file added docs/resources/dicestats_2d20kh1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/resources/dicestats_2d20kh1_4d6dl1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,20 @@ dependencies:
- safe
- edit-distance
- unliftio
- Chart
- Chart-diagrams
- diagrams-core
- diagrams-lib
- diagrams-rasterific
- JuicyPixels
- split
- regex-pcre
- distribution

library:
source-dirs: src
default-extensions:
- OverloadedStrings
- ImportQualifiedPost
- LambdaCase
- EmptyDataDecls
- FlexibleContexts
Expand All @@ -88,6 +94,7 @@ library:
- ScopedTypeVariables
- TypeOperators
- RankNTypes
- BangPatterns
ghc-options:
- -Wall

Expand Down
2 changes: 1 addition & 1 deletion src/Tablebot/Internal/Handler/Command.hs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ makeReadable (TrivialError i _ good) =
getLabel :: [ErrorItem (Token Text)] -> (Maybe String, [String])
getLabel [] = (Nothing, [])
getLabel ((Tokens nel) : xs) = (Nothing, [NE.toList nel]) <> getLabel xs
getLabel ((Label ls) : xs) = (Just (NE.toList ls), []) <> getLabel xs
getLabel ((Label ls) : xs) = (Just (NE.toList ls <> "\n"), []) <> getLabel xs
getLabel (EndOfInput : xs) = (Nothing, ["no more input"]) <> getLabel xs
makeReadable e = (mapParseError (const UnknownError) e, Nothing)

Expand Down
15 changes: 13 additions & 2 deletions src/Tablebot/Plugins/Roll/Dice/DiceData.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,21 @@ data ArgValue = AVExpr Expr | AVListValues ListValues
deriving (Show)

-- | The type for list values.
data ListValues = MultipleValues NumBase Base | LVFunc (FuncInfoBase IO [Integer]) [ArgValue] | LVBase ListValuesBase
data ListValues
= -- | Represents `N#B`, where N is a NumBase (numbers, parentheses) and B is a Base (numbase or dice value)
MultipleValues NumBase Base
| -- | Represents a function call with the given arguments
LVFunc (FuncInfoBase [Integer]) [ArgValue]
| -- | A base ListValues value - parentheses or a list of expressions
LVBase ListValuesBase
deriving (Show)

-- | The type for basic list values (that can be used as is for custom dice).
--
-- A basic list value can be understood as one that is indivisible, and/or
-- atomic. They represent either a list value in parentheses, or a list of
-- expressions. Effectively what this is used for is so that these can be used
-- as dice side values.
data ListValuesBase = LVBParen (Paren ListValues) | LVBList [Expr]
deriving (Show)

Expand All @@ -47,7 +58,7 @@ data Expo = Expo Func Expo | NoExpo Func
deriving (Show)

-- | The type representing a single function application, or a base item.
data Func = Func (FuncInfo IO) [ArgValue] | NoFunc Base
data Func = Func FuncInfo [ArgValue] | NoFunc Base
deriving (Show)

-- | The type representing an integer value or an expression in brackets.
Expand Down
11 changes: 8 additions & 3 deletions src/Tablebot/Plugins/Roll/Dice/DiceEval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
--
-- Functions, type classes, and other utilities to evaluate dice values and
-- expressions.
module Tablebot.Plugins.Roll.Dice.DiceEval (PrettyShow (prettyShow), evalList, evalInteger) where
module Tablebot.Plugins.Roll.Dice.DiceEval (PrettyShow (prettyShow), evalList, evalInteger, evaluationException, propagateException) where

import Control.Monad (when)
import Control.Monad.Exception (MonadException)
Expand Down Expand Up @@ -37,6 +37,9 @@ newtype RNGCount = RNGCount {getRNGCount :: Integer} deriving (Eq, Ord)
maximumRNG :: RNGCount
maximumRNG = RNGCount 150

maximumListLength :: Integer
maximumListLength = 50

-- | Increment the rngcount by 1.
incRNGCount :: RNGCount -> RNGCount
incRNGCount (RNGCount i) = RNGCount (i + 1)
Expand Down Expand Up @@ -136,7 +139,9 @@ class IOEvalList a where
-- displayed. This function adds the current location to the exception
-- callstack.
evalShowL :: PrettyShow a => RNGCount -> a -> IO ([(Integer, Text)], Maybe Text, RNGCount)
evalShowL rngCount a = propagateException (prettyShow a) (evalShowL' rngCount a)
evalShowL rngCount a = do
(is, mt, rngCount') <- propagateException (prettyShow a) (evalShowL' rngCount a)
return (genericTake maximumListLength is, mt, rngCount')

evalShowL' :: PrettyShow a => RNGCount -> a -> IO ([(Integer, Text)], Maybe Text, RNGCount)

Expand Down Expand Up @@ -359,7 +364,7 @@ instance IOEval Func where
evalShow' rngCount (NoFunc b) = evalShow rngCount b

-- | Evaluate a function when given a list of parameters
evaluateFunction :: RNGCount -> FuncInfoBase IO j -> [ArgValue] -> IO (j, Text, RNGCount)
evaluateFunction :: RNGCount -> FuncInfoBase j -> [ArgValue] -> IO (j, Text, RNGCount)
evaluateFunction rngCount fi exprs = do
(exprs', rngCount') <- evalShowList'' (\r a -> evalArgValue r a >>= \(i, r') -> return (i, "", r')) rngCount exprs
f <- funcInfoFunc fi (fst <$> exprs')
Expand Down
60 changes: 41 additions & 19 deletions src/Tablebot/Plugins/Roll/Dice/DiceFunctions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ factorialLimit = 50

-- | Mapping from function names to the functions themselves for integer
-- functions.
integerFunctions :: MonadException m => Map Text (FuncInfo m)
integerFunctions :: Map Text FuncInfo
integerFunctions = M.fromList $ fmap (\fi -> (funcInfoName fi, fi)) integerFunctions'

-- | The names of the integer functions currently supported.
integerFunctionsList :: [Text]
integerFunctionsList = M.keys (integerFunctions @IO)
integerFunctionsList = M.keys integerFunctions

-- | The base details of the integer functions, containing all the information
-- for each function that returns an integer.
integerFunctions' :: MonadException m => [FuncInfo m]
integerFunctions' :: [FuncInfo]
integerFunctions' =
funcInfoIndex :
constructFuncInfo "length" (genericLength @Integer @Integer) :
constructFuncInfo "sum" (sum @[] @Integer) :
constructFuncInfo "max" (max @Integer) :
constructFuncInfo "min" (min @Integer) :
constructFuncInfo "maximum" (maximum @[] @Integer) :
constructFuncInfo "minimum" (minimum @[] @Integer) :
constructFuncInfo' "mod" (mod @Integer) (Nothing, Nothing, (== 0)) :
Expand All @@ -63,23 +65,27 @@ integerFunctions' =
| otherwise = n * fact (n - 1)

-- | Mapping from function names to the functions themselves for list functions.
listFunctions :: MonadException m => Map Text (FuncInfoBase m [Integer])
listFunctions :: Map Text (FuncInfoBase [Integer])
listFunctions = M.fromList $ fmap (\fi -> (funcInfoName fi, fi)) listFunctions'

-- | The names of the list functions currently supported.
listFunctionsList :: [Text]
listFunctionsList = M.keys (listFunctions @IO)
listFunctionsList = M.keys listFunctions

-- | The base details of the list functions, containing all the information for
-- each function that returns an integer.
listFunctions' :: MonadException m => [FuncInfoBase m [Integer]]
listFunctions' :: [FuncInfoBase [Integer]]
listFunctions' =
constructFuncInfo @[Integer] "drop" (genericDrop @Integer) :
constructFuncInfo "concat" (++) :
constructFuncInfo "between" between :
constructFuncInfo "drop" (genericDrop @Integer) :
constructFuncInfo "take" (genericTake @Integer) :
(uncurry constructFuncInfo <$> [("sort", sort), ("reverse", reverse)])
where
between i i' = let (mi, ma, rev) = (min i i', max i i', if i > i' then reverse else id) in rev [mi .. ma]

-- | The `FuncInfo` of the function that indexes into a list.
funcInfoIndex :: FuncInfo m
funcInfoIndex :: FuncInfo
funcInfoIndex = FuncInfo "index" [ATInteger, ATIntegerList] ATInteger fiIndex
where
fiIndex (LIInteger i : [LIList is])
Expand All @@ -89,20 +95,20 @@ funcInfoIndex = FuncInfo "index" [ATInteger, ATIntegerList] ATInteger fiIndex

-- | A data structure to contain the information about a given function,
-- including types, the function name, and the function itself.
data FuncInfoBase m j = FuncInfo {funcInfoName :: Text, funcInfoParameters :: [ArgType], funcReturnType :: ArgType, funcInfoFunc :: MonadException m => [ListInteger] -> m j}
data FuncInfoBase j = FuncInfo {funcInfoName :: Text, funcInfoParameters :: [ArgType], funcReturnType :: ArgType, funcInfoFunc :: forall m. (MonadException m) => [ListInteger] -> m j}

type FuncInfo m = FuncInfoBase m Integer
type FuncInfo = FuncInfoBase Integer

instance Show (FuncInfoBase m j) where
instance Show (FuncInfoBase j) where
show (FuncInfo fin ft frt _) = "FuncInfo " <> unpack fin <> " " <> show ft <> " " <> show frt

-- | A simple way to construct a function that returns a value j, and has no
-- constraints on the given values.
constructFuncInfo :: forall j f m. (MonadException m, ApplyFunc m f, Returns f ~ j) => Text -> f -> FuncInfoBase m j
constructFuncInfo :: forall j f. (ApplyFunc f, Returns f ~ j) => Text -> f -> FuncInfoBase j
constructFuncInfo s f = constructFuncInfo' s f (Nothing, Nothing, const False)

-- | Construct a function info when given optional constraints.
constructFuncInfo' :: forall j f m. (MonadException m, ApplyFunc m f, Returns f ~ j) => Text -> f -> (Maybe Integer, Maybe Integer, Integer -> Bool) -> FuncInfoBase m j
constructFuncInfo' :: forall j f. (ApplyFunc f, Returns f ~ j) => Text -> f -> (Maybe Integer, Maybe Integer, Integer -> Bool) -> FuncInfoBase j
constructFuncInfo' s f bs = FuncInfo s params (last types) (applyFunc f (fromIntegral (length params)) bs)
where
types = getTypes f
Expand Down Expand Up @@ -144,12 +150,16 @@ instance ArgCount f => ArgCount ([Integer] -> f) where
--
-- If the number of inputs is incorrect or the value given out of the range, an
-- exception is thrown.
class ArgCount f => ApplyFunc m f where
class ArgCount f => ApplyFunc f where
-- | Takes a function, the number of arguments in the function overall, bounds
-- on integer values to the function, and a list of `ListInteger`s (which are
-- either a list of integers or an integer), and returns a wrapped `j` value,
-- which is a value that the function originally returns.
L0neGamer marked this conversation as resolved.
Show resolved Hide resolved
applyFunc :: (MonadException m, Returns f ~ j) => f -> Integer -> (Maybe Integer, Maybe Integer, Integer -> Bool) -> [ListInteger] -> m j
--
-- The bounds represent the exclusive lower bound, the exclusive upper bound,
-- and an arbitrary function which results in an exception when it is true;
-- say, with division when you want to deny just 0 as a value.
applyFunc :: forall m j. (MonadException m, Returns f ~ j) => f -> Integer -> (Maybe Integer, Maybe Integer, Integer -> Bool) -> [ListInteger] -> m j

-- | Check whether a given value is within the given bounds.
checkBounds :: (MonadException m) => Integer -> (Maybe Integer, Maybe Integer, Integer -> Bool) -> m Integer
Expand All @@ -159,22 +169,34 @@ checkBounds i (ml, mh, bs)
| bs i = throwBot $ EvaluationException ("invalid value for function: `" <> show i ++ "`") []
| otherwise = return i

instance {-# OVERLAPPING #-} ApplyFunc m Integer where
-- This is one of two base cases for applyFunc. This is the case where the
-- return value is an integer. As it is the return value, no arguments are
-- accepted.
instance {-# OVERLAPPING #-} ApplyFunc Integer where
L0neGamer marked this conversation as resolved.
Show resolved Hide resolved
applyFunc f _ _ [] = return f
applyFunc _ args _ _ = throwBot $ EvaluationException ("incorrect number of arguments to function. expected " <> show args <> ", got more than that") []

instance {-# OVERLAPPING #-} ApplyFunc m [Integer] where
-- This is one of two base cases for applyFunc. This is the case where the
-- return value is a list of integers. As it is the return value, no arguments
-- are accepted.
instance {-# OVERLAPPING #-} ApplyFunc [Integer] where
applyFunc f _ _ [] = return f
applyFunc _ args _ _ = throwBot $ EvaluationException ("incorrect number of arguments to function. expected " <> show args <> ", got more than that") []

instance {-# OVERLAPPABLE #-} (ApplyFunc m f) => ApplyFunc m (Integer -> f) where
-- This is one of two recursive cases for applyFunc. This is the case where the
-- argument value is an integer. If there are no arguments or the argument is
-- of the wrong type, an exception is thrown.
instance {-# OVERLAPPABLE #-} (ApplyFunc f) => ApplyFunc (Integer -> f) where
applyFunc f args _ [] = throwBot $ EvaluationException ("incorrect number of arguments to function. got " <> show dif <> ", expected " <> show args) []
where
dif = args - getArgs f
applyFunc f args bs ((LIInteger x) : xs) = checkBounds x bs >>= \x' -> applyFunc (f x') args bs xs
applyFunc _ _ _ (_ : _) = throwBot $ EvaluationException "incorrect type given to function. expected an integer, got a list" []

instance {-# OVERLAPPABLE #-} (ApplyFunc m f) => ApplyFunc m ([Integer] -> f) where
-- This is one of two recursive cases for applyFunc. This is the case where the
-- argument value is a list of integers. If there are no arguments or the
-- argument is of the wrong type, an exception is thrown.
instance {-# OVERLAPPABLE #-} (ApplyFunc f) => ApplyFunc ([Integer] -> f) where
applyFunc f args _ [] = throwBot $ EvaluationException ("incorrect number of arguments to function. got " <> show dif <> ", expected " <> show args) []
where
dif = args - getArgs f
Expand Down
Loading