packages feed

zwirn-0.1.0.0: src/Zwirn/Language/Builtin/Prelude.hs

{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-orphans #-}

module Zwirn.Language.Builtin.Prelude where

{-
    Builtin.hs - defines builtin functions
    Copyright (C) 2023, Martin Gius

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
-}

import qualified Data.Map as Map
import Data.Text (Text)
import Zwirn.Core.Conditional as Z
import Zwirn.Core.Cord as C
import Zwirn.Core.Core as C
import Zwirn.Core.Map as M
import Zwirn.Core.Modulate
import Zwirn.Core.Number as N
import Zwirn.Core.Random
import Zwirn.Core.Structure as S
import Zwirn.Core.Time
import Zwirn.Language.Builtin.Internal
import Zwirn.Language.Builtin.Parameters
import Zwirn.Language.Environment
import Zwirn.Language.Evaluate hiding (insert)
import Zwirn.Language.TypeCheck.Types

builtinEnvironment :: InterpreterEnv
builtinEnvironment = IEnv builtins instances

instances :: [Instance]
instances =
  [ IsIn "Num" numberT,
    IsIn "Num" mapT,
    IsIn "Eq" numberT,
    IsIn "Eq" mapT,
    IsIn "Eq" textT
  ]

builtinNames :: [Text]
builtinNames = Map.keys builtins

builtins :: Map.Map Text AnnotatedExpression
builtins =
  Map.unions
    [ coreFunctions,
      numberFunctions,
      signals,
      randomFunctions,
      timeFunctions,
      structureFunctions,
      conditionalFunctions,
      cordFunctions,
      mapFunctions,
      stateFunctions,
      builtinParams
    ]

coreFunctions :: Map.Map Text AnnotatedExpression
coreFunctions =
  Map.unions
    [ "id"
        === lambda id
        <:: "a -> a"
        --| "identity function",
      "const"
        === lambda (lambda . const)
        <:: "a -> b -> a"
        --| "constant function - ignore second input",
      "scomb"
        === lambda (\f -> lambda $ \g -> lambda $ \x -> f ! x ! (g ! x))
        <:: "(a -> b -> c) -> (a -> b) -> a -> c"
        --| "S-combinator",
      "."
        === lambda (\g -> lambda $ \f -> lambda $ \x -> g ! (f ! x))
        <:: "(b -> c) -> (a -> b) -> a -> c"
        --| "function composition",
      "flip"
        === lambda (\f -> lambda $ \y -> lambda $ \x -> f ! x ! y)
        <:: "(a -> b -> c) -> b -> a -> c"
        --| "flip arguments",
      "\'"
        === toExp (flip squeezeApply :: Zwirn Expression -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression)
        <:: "a -> (a -> b) -> b"
        --| "apply argument to function, results are squeezed",
      "$"
        === toExp (squeezeApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply argument to function, results are squeezed",
      "|$"
        === toExp (outerApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply argument to function",
      "$|"
        === toExp (innerApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply argument to function",
      "map"
        === toExp (mapZ :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "map a function over the structure of the argument",
      "zip"
        === toExp (zipApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "map a function over the structure of the argument",
      "bus"
        === toExp (id :: Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Bus"
        --| "controlbus",
      "recv"
        === toExp (toExp recv)
        <:: "Text -> Number -> Map"
        --| "recieve a value from a bus and send it to the given parameter"
    ]

numberFunctions :: Map.Map Text AnnotatedExpression
numberFunctions =
  Map.unions
    [ "|+"
        === toExp ((+) :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a -> a"
        --| "addition",
      "|-"
        === toExp ((-) :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a -> a"
        --| "subtraction",
      "|*"
        === toExp ((*) :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a -> a"
        --| "multiplication",
      "|/"
        === toExp ((/) :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a -> a"
        --| "division",
      "negate"
        === toExp (negate :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "negate",
      "abs"
        === toExp (abs :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "absolute value",
      "signum"
        === toExp (signum :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a =>  a -> a"
        --| "signum",
      "recip"
        === toExp (recip :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "reciprocal value",
      "pi"
        === toExp (pi :: Zwirn Expression)
        <:: "Number"
        --| "pi",
      "|**"
        === toExp ((**) :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a -> a"
        --| "exponentiation",
      "exp"
        === toExp (exp :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "exponential function",
      "log"
        === toExp (log :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "logarithm base 10",
      "sqrt"
        === toExp (sqrt :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a =>  a -> a"
        --| "square root",
      "sin"
        === toExp (sin :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "sine function",
      "cos"
        === toExp (cos :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "cosine function",
      "tan"
        === toExp (tan :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "tangens",
      "asin"
        === toExp (asin :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "arc sine function",
      "acos"
        === toExp (acos :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "arc cosine function",
      "atan"
        === toExp (atan :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "arc tangens",
      "sinh"
        === toExp (sinh :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "hyperbolic sine",
      "cosh"
        === toExp (cosh :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a =>  a -> a"
        --| "hyperbolic cosine",
      "tanh"
        === toExp (tan :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "hyperbolic tangens",
      "asinh"
        === toExp (asinh :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "hyperbolic arc sine function",
      "acosh"
        === toExp (acosh :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "hyperbolic arc cosine function",
      "atanh"
        === toExp (atanh :: Zwirn Expression -> Zwirn Expression)
        <:: "Num a => a -> a"
        --| "hyperbolic arc tangens",
      "mod"
        === toExp (N.mod :: Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number"
        --| "modulo",
      "frac"
        === toExp (N.frac :: Zwirn Double -> Zwirn Double)
        <:: "Number -> Number"
        --| "fractional part of a number",
      "trunc"
        === toExp (N.trunc :: Zwirn Double -> Zwirn Int)
        <:: "Number -> Number"
        --| "truncate",
      "ceil"
        === toExp (N.ceil :: Zwirn Double -> Zwirn Int)
        <:: "Number -> Number"
        --| "round up",
      "floor"
        === toExp (N.floor :: Zwirn Double -> Zwirn Int)
        <:: "Number -> Number"
        --| "round down",
      "round"
        === toExp (N.round :: Zwirn Double -> Zwirn Int)
        <:: "Number -> Number"
        --| "round to closest",
      "gcd"
        === toExp (N.gcd :: Zwirn Int -> Zwirn Int -> Zwirn Int)
        <:: "Number -> Number -> Number"
        --| "greatest common divisor",
      "lcm"
        === toExp (N.lcm :: Zwirn Int -> Zwirn Int -> Zwirn Int)
        <:: "Number -> Number -> Number"
        --| "least common multiple",
      "range"
        === toExp (range :: Zwirn Double -> Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number -> Number"
        --| "range x y l maps number l linearly into interval (x,y), assuming l is between 0 and 1"
    ]

signals :: Map.Map Text AnnotatedExpression
signals =
  Map.unions
    [ "sine"
        === toExp (sine :: Zwirn Time)
        <:: "Number"
        --| "sine signal",
      "sine2"
        === toExp (sine2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar sine signal",
      "saw"
        === toExp (saw :: Zwirn Time)
        <:: "Number"
        --| "saw signal",
      "saw2"
        === toExp (saw2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar saw signal",
      "cosine"
        === toExp (cosine :: Zwirn Time)
        <:: "Number"
        --| "cosine signal",
      "cosine2"
        === toExp (cosine2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar cosine signal",
      "isaw"
        === toExp (isaw :: Zwirn Time)
        <:: "Number"
        --| "inverse saw signal",
      "isaw2"
        === toExp (isaw2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar inverse saw signal",
      "tri"
        === toExp (tri :: Zwirn Time)
        <:: "Number"
        --| "triangle signal",
      "tri2"
        === toExp (tri2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar triangle signal",
      "square"
        === toExp (square :: Zwirn Time)
        <:: "Number"
        --| "square signal",
      "square2"
        === toExp (square2 :: Zwirn Time)
        <:: "Number"
        --| "bipolar square signal"
    ]

randomFunctions :: Map.Map Text AnnotatedExpression
randomFunctions =
  Map.unions
    [ "noise"
        === toExp (noise :: Zwirn Double)
        <:: "Number"
        --| "random stream of values between 0 and 1",
      "irand"
        === toExp (irand :: Zwirn Int -> Zwirn Int)
        <:: "Number -> Number"
        --| "random integer values between 0 and given input",
      "chooseFromTo"
        === toExp (enumFromToChoice 0 :: Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number"
        --| "```chooseFromTo x y == [x | .. y]```",
      "chooseFromThenTo"
        === toExp (enumFromThenToChoice 0 :: Zwirn Double -> Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number -> Number"
        --| "```chooseFromTo x y z == [x | y .. z]```"
    ]

timeFunctions :: Map.Map Text AnnotatedExpression
timeFunctions =
  Map.unions
    [ "*"
        === toExp (flip fast :: Zwirn Expression -> Zwirn Time -> Zwirn Expression)
        <:: "a -> Number -> a"
        --| "multiply time, making it faster",
      "fast"
        === toExp (fast :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "multiply time, making it faster",
      "/"
        === toExp (flip slow :: Zwirn Expression -> Zwirn Time -> Zwirn Expression)
        <:: "a -> Number -> a"
        --| "divide time, making it slower",
      "slow"
        === toExp (slow :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "divide time, making it slower",
      "+"
        === toExp (flip shift :: Zwirn Expression -> Zwirn Time -> Zwirn Expression)
        <:: "a -> Number -> a"
        --| "shift time to the right",
      "-"
        === toExp (flip (shift . fmap negate) :: Zwirn Expression -> Zwirn Time -> Zwirn Expression)
        <:: "a -> Number -> a"
        --| "shift time to the left",
      "shift"
        === toExp (shift :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "shift time",
      "revBy"
        === toExp (revBy :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "reverse time, piecewise",
      "rev"
        === toExp (rev :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "reverse time completely",
      "ply"
        === toExp (ply :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "speed up time inside",
      "timeloop"
        === toExp (timeloop :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "loop time from 0 to the given number",
      "zoom"
        === toExp (zoom :: Zwirn Time -> Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "zoom and loop a part of a zwirn"
    ]

structureFunctions :: Map.Map Text AnnotatedExpression
structureFunctions =
  Map.unions
    [ "euclidOff"
        === toExp (euclidOff :: Zwirn Int -> Zwirn Int -> Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> Number -> a -> a"
        --| "shifted euclidean rhythm",
      "euclid"
        === toExp (euclid :: Zwirn Int -> Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "euclidean rhythm",
      "segment"
        === toExp (segment :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "divide structure into equal pieces",
      "struct"
        === toExp (struct :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "a -> b -> b"
        --| "copy the structure from first value",
      "run"
        === toExp (run :: Zwirn Int -> Zwirn Int)
        <:: "Number -> Number"
        --| "```run n == [0 .. n-1]```",
      "runFromTo"
        === toExp (runFromTo :: Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number"
        --| "```runFromTo x y == [x .. y]```",
      "runFromThenTo"
        === toExp (runFromThenTo :: Zwirn Double -> Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number -> Number"
        --| "```runFromTo x y z == [x y ..  z]```",
      "slowrun"
        === toExp (slowrun :: Zwirn Int -> Zwirn Int)
        <:: "Number -> Number"
        --| "```run n == <0 .. n-1>```",
      "slowrunFromTo"
        === toExp (slowrunFromTo :: Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number"
        --| "```slowrunFromTo x y == <x .. y>```",
      "slowrunFromThenTo"
        === toExp (slowrunFromThenTo :: Zwirn Double -> Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number -> Number"
        --| "```slowrunFromTo x y z == <x y ..  z>```"
    ]

conditionalFunctions :: Map.Map Text AnnotatedExpression
conditionalFunctions =
  Map.unions
    [ "=="
        === toExp (eq :: Zwirn Expression -> Zwirn Expression -> Zwirn Bool)
        <:: "Eq a => a -> a -> Number"
        --| "equality",
      ">="
        === toExp (geq :: Zwirn Expression -> Zwirn Expression -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "greater or equal",
      "<="
        === toExp (leq :: Zwirn Expression -> Zwirn Expression -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "less or equal",
      "<"
        === toExp (ge :: Zwirn Expression -> Zwirn Expression -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "less",
      ">"
        === toExp (le :: Zwirn Expression -> Zwirn Expression -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "greater",
      "not"
        === toExp (Z.not :: Zwirn Bool -> Zwirn Bool)
        <:: "Number -> Number"
        --| "logical not",
      "&&"
        === toExp (Z.and :: Zwirn Bool -> Zwirn Bool -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "logical and",
      "||"
        === toExp (Z.or :: Zwirn Bool -> Zwirn Bool -> Zwirn Bool)
        <:: "Number -> Number -> Number"
        --| "logical or",
      "ifthen"
        === toExp (ifthen :: Zwirn Bool -> Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a -> a"
        --| "choose between two expressions based on a condition",
      "if"
        === toExp (iff :: Zwirn Bool -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "if condition is true produce the value, silence otherwise",
      "while"
        === toExp (while :: Zwirn Bool -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "apply function while condition is true",
      "everyFor"
        === toExp (everyFor :: Zwirn Time -> Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> (a -> a) -> a -> a"
        --| "apply function periodically for a given amount of time",
      "every"
        === toExp (every :: Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "apply function periodically for one cycle"
    ]

cordFunctions :: Map.Map Text AnnotatedExpression
cordFunctions =
  Map.unions
    [ "project"
        === toExp (project :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "project to a certain layer of a cord",
      "insert"
        === toExp (C.insert :: Zwirn Int -> Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a -> a"
        --| "insert into a specific layer of a cord",
      "remove"
        === toExp (remove :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "remove a specific layer of a cord",
      "arp"
        === toExp (arp :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "arpeggiate",
      "reverse"
        === toExp (reverseC :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "reverse order of cord",
      "invert"
        === toExp (invertC :: Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number"
        --| "chord inversion",
      "rotate"
        === toExp (rotateC :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "cord rotation",
      "at"
        === toExp (at :: Zwirn Int -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "apply a function to a specific layer of a cord",
      "cordFromTo"
        === toExp (enumFromToStack :: Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number"
        --| "```cordFromTo x y == [x, .. y]```",
      "cordFromThenTo"
        === toExp (enumFromThenToStack :: Zwirn Double -> Zwirn Double -> Zwirn Double -> Zwirn Double)
        <:: "Number -> Number -> Number -> Number"
        --| "```cordFromThenTo x y z == [x, y .. z]```"
    ]

mapFunctions :: Map.Map Text AnnotatedExpression
mapFunctions =
  Map.unions
    [ "pN"
        === toExp ((\t -> fmap toExp . singleton t) :: Zwirn Text -> Zwirn Double -> Zwirn Expression)
        <:: "Text -> Number -> Map"
        --| "number singleton with specific key",
      "pT"
        === toExp ((\t -> fmap toExp . singleton t) :: Zwirn Text -> Zwirn Text -> Zwirn Expression)
        <:: "Text -> Text -> Map"
        --| "text singleton with specific key",
      "#"
        === toExp (union :: Zwirn ExpressionMap -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Map -> Map -> Map"
        --| "union of two maps - structure from the left",
      "lookupN"
        === toExp (M.lookup :: Zwirn Text -> Zwirn ExpressionMap -> Zwirn Expression)
        <:: "Text -> Map -> Number"
        --| "retrieve number at given key or silence if key is missing or it's value not a number",
      "lookupT"
        === toExp (M.lookup :: Zwirn Text -> Zwirn ExpressionMap -> Zwirn Expression)
        <:: "Text -> Map -> Text"
        --| "retrieve text at given key or silence if key is missing or it's value not a text",
      "fix"
        === toExp (M.fix :: Zwirn Text -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Text -> (Map -> Map) -> Map -> Map"
        --| "apply a function to a specific key",
      "loopAt"
        === toExp (loopAt :: Zwirn Time -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Map -> Map"
        --| "",
      "slice"
        === toExp (slice :: Zwirn Int -> Zwirn Int -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Number -> Map -> Map"
        --| "slice a sample into equal btis and index into them",
      "chop"
        === toExp (chop :: Zwirn Int -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Map -> Map"
        --| "",
      "striate"
        === toExp (striate :: Zwirn Int -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Map -> Map"
        --| "",
      "striateBy"
        === toExp (striateBy :: Zwirn Int -> Zwirn Expression -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Number -> Map -> Map"
        --| ""
    ]

stateFunctions :: Map.Map Text AnnotatedExpression
stateFunctions =
  Map.unions
    [ "getN"
        === toExp getStateN
        <:: "Text -> Number"
        --| "retrieve number from state at given key or silence if key is missing or it's value not a number",
      "getT"
        === toExp getStateT
        <:: "Text -> Text"
        --| "retrieve text from state at given key or silence if key is missing or it's value not a text",
      "getM"
        === toExp getStateM
        <:: "Text -> Map"
        --| "retrieve map from state at given key or silence if key is missing or it's value not a map",
      "set"
        === toExp setState
        <:: "Text -> a -> b -> b"
        --| "set state at key to given value",
      "modify"
        === toExp modifyState
        <:: "Text -> (a -> a) -> b -> b"
        --| "modify state at given key with function"
    ]