packages feed

zwirn-0.2.2.0: src/zwirn-lang/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.Lib.Conditional as Z
import Zwirn.Core.Lib.Cord as C
import Zwirn.Core.Lib.Core as C
import Zwirn.Core.Lib.Map as M
import Zwirn.Core.Lib.Modulate
import Zwirn.Core.Lib.Number as N
import Zwirn.Core.Lib.Random
import Zwirn.Core.Lib.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
import Zwirn.Stream.Types (Stream)

builtinEnvironment :: InterpreterEnv
builtinEnvironment = IEnv builtins instances

builtinEnvironmentWithStream :: Stream -> InterpreterEnv
builtinEnvironmentWithStream str = IEnv (Map.unions [builtins, streamFunctions str]) instances

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

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

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

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 apply :: Zwirn Expression -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression)
        <:: "a -> (a -> b) -> b"
        --| "apply argument to function, results are squeezed and zipped",
      "($)"
        === toExp (apply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply function to argument, results are squeezed and zipped",
      "match"
        === toExp (matchApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "",
      "iterate"
        === toExp (C.iterate :: Zwirn Int -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "apply function to argument, n times",
      "(|$)"
        === toExp (outerApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply function to argument",
      "($|)"
        === toExp (innerApply :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply function to argument",
      "squeeze"
        === toExp (squeeze :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "map a function over the structure of the argument",
      "inner"
        === toExp (getInnerTime :: Zwirn Expression -> Zwirn Double)
        <:: "a -> Number"
        --| "get the inner time of a zwirn",
      "diff"
        === toExp (getSpeed :: Zwirn Expression -> Zwirn Double)
        <:: "a -> Number"
        --| "get the speed of a zwirn",
      "trig"
        === toExp (trig :: Zwirn Expression -> Zwirn Bool)
        <:: "a -> Number"
        --| "returns true on the trigger points, false otherwise",
      "recv"
        === toExp recv
        <:: "(Number -> Map) -> Number -> Map"
        --| "recieve a value from a bus and send it to the given parameter",
      "recvT"
        === toExp recvT
        <:: "Text -> Number -> Map"
        --| "like recv but takes the parameter name as text"
    ]

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
    [ "now"
        === toExp (now :: Zwirn Time)
        <:: "Number"
        --| "current time",
      "cyc"
        === toExp (C.cyc :: Zwirn Int)
        <:: "Number"
        --| "current cycle",
      "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",
      "firstCyclesThen"
        === toExp (firstCyclesThen :: Zwirn Time -> Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a -> a"
        --| "bipolar square signal"
    ]

randomFunctions :: Map.Map Text AnnotatedExpression
randomFunctions =
  Map.unions
    [ "rand"
        === toExp (noise :: Zwirn Double)
        <:: "Number"
        --| "random stream of values between 0 and 1",
      "brand"
        === toExp (rand :: Zwirn Bool)
        <:: "Number"
        --| "random binary choice",
      "brandBy"
        === toExp (brandBy :: Zwirn Double -> Zwirn Bool)
        <:: "Number -> Number"
        --| "weighted random binary choice",
      "irand"
        === toExp (irand :: Zwirn Int -> Zwirn Int)
        <:: "Number -> Number"
        --| "random integer values between 0 and given input",
      "cycrand"
        === toExp (rand' :: Zwirn Double)
        <:: "Number"
        --| "random stream of values between 0 and 1, one value per cycle",
      "cycbrand"
        === toExp (rand :: Zwirn Bool)
        <:: "Number"
        --| "random binary cyclewise choice",
      "cycbrandBy"
        === toExp (brandBy' :: Zwirn Double -> Zwirn Bool)
        <:: "Number -> Number"
        --| "weighted random binary cyclewise choice",
      "cycirand"
        === toExp (irand' :: Zwirn Int -> Zwirn Int)
        <:: "Number -> Number"
        --| "random integer values between 0 and given input, one value per cycle",
      "perlin"
        === toExp (perlin :: Zwirn Double)
        <:: "Number"
        --| "perlin noise between 0 and 1",
      "simplex"
        === toExp (simplex :: Zwirn Double)
        <:: "Number"
        --| "simplex noise between 0 and 1",
      "ssimplex"
        === toExp (ssimplex :: Zwirn Double)
        <:: "Number"
        --| "super simplex noise between 0 and 1",
      "value"
        === toExp (valueN :: Zwirn Double)
        <:: "Number"
        --| "value noise between 0 and 1",
      "cubic"
        === toExp (cubic :: Zwirn Double)
        <:: "Number"
        --| "cubic value noise between 0 and 1",
      "perlinS"
        === toExp (perlinSeed :: Zwirn Int -> Zwirn Double)
        <:: "Number -> Number"
        --| "seeded perlin noise between 0 and 1",
      "simplexS"
        === toExp (simplexSeed :: Zwirn Int -> Zwirn Double)
        <:: "Number -> Number"
        --| "seeded simplex noise between 0 and 1",
      "ssimplexS"
        === toExp (ssimplexSeed :: Zwirn Int -> Zwirn Double)
        <:: "Number -> Number"
        --| "seeded super simplex noise between 0 and 1",
      "valueS"
        === toExp (valueSeed :: Zwirn Int -> Zwirn Double)
        <:: "Number -> Number"
        --| "seeded value noise between 0 and 1",
      "cubicS"
        === toExp (cubicSeed :: Zwirn Int -> Zwirn Double)
        <:: "Number -> Number"
        --| "seeded cubic value noise between 0 and 1",
      "somecyclesBy"
        === toExp (somecyclesBy :: Zwirn Double -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> b) -> a -> b"
        --| "apply a function with a given chance per cycle",
      "somecycles"
        === toExp (somecycles :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a functions with a 50% chance per cycle",
      "sometimesBy"
        === toExp (sometimesBy :: Zwirn Double -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> b) -> a -> b"
        --| "apply a function with a given chance",
      "sometimes"
        === toExp (sometimes :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a function with a 50% chance",
      "often"
        === toExp (often :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a function with a 75% chance",
      "rarely"
        === toExp (rarely :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a function with a 25% chance",
      "almostNever"
        === toExp (almostNever :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a function with a 10% chance",
      "almostAlways"
        === toExp (almostNever :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "apply a function with a 90% chance",
      "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",
      "bump"
        === toExp (bump :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "shift time inside",
      "timeloop"
        === toExp (timeloop :: Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "loop time from 0 to the given number",
      "loop"
        === toExp (loop :: Zwirn Time -> Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "loop a specifc range of a zwirn, speeding up",
      "ribbon"
        === toExp (ribbon :: Zwirn Time -> Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "given an offset and a length, loops the according region",
      "zoom"
        === toExp (zoom :: Zwirn Time -> Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "zoom and loop a part of a zwirn",
      "swingBy"
        === toExp (swingBy :: Zwirn Time -> Zwirn Time -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> a -> a"
        --| "given a swing amount and a number of subdivisions, shifts the second half of every subdivion by the given amount, creating a swing feel."
    ]

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",
      "euclideanOff"
        === toExp (euclidean :: Zwirn Int -> Zwirn Int -> Zwirn Int -> Zwirn String)
        <:: "Number -> Number -> Number -> Text"
        --| "string representation of shifted euclidean rhythm",
      "euclidean"
        === toExp ((euclidean $ pure 0) :: Zwirn Int -> Zwirn Int -> Zwirn String)
        <:: "Number -> Number -> Number -> Text"
        --| "string representation of euclidean rhythm",
      "binary"
        === toExp (binary :: Zwirn Int -> Zwirn String)
        <:: "Number -> Text"
        --| "converts number to binary sequence",
      "christoffel"
        === toExp (christoffel :: Zwirn Int -> Zwirn Int -> Zwirn String)
        <:: "Number -> Number -> Text"
        --| "create the two alphabet christoffel word",
      "neg"
        === toExp (neg :: Zwirn String -> Zwirn String)
        <:: "Text -> Text"
        --| "make onsets to offsets in chunk notation",
      -- "rotate"
      --   === toExp (rotate :: Zwirn Int -> Zwirn String -> Zwirn String)
      --   <:: "Number -> Text -> Text"
      --   --| "rotate characters in a string by amount",
      "chunkWith"
        === toExp (chunkWith :: Zwirn Double -> Zwirn String -> Zwirn Int)
        <:: "Number -> Text -> Number"
        --| "converts from Boenn's chunk notation to a rhythm",
      "chunk"
        === toExp (chunk :: Zwirn String -> Zwirn Int)
        <:: "Text -> Number"
        --| "converts from Boenn's chunk notation to a rhythm",
      "chunked"
        === toExp (chunked :: Zwirn String -> Zwirn Expression -> Zwirn Expression)
        <:: "Text -> a -> a"
        --| "converts from Boenn's chunk notation to a rhythm",
      "segment"
        === toExp (segment :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "divide structure into equal pieces",
      "sample"
        === toExp (sampleAndHold :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "like segment, but the values are held ('sample and hold')",
      "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",
      "everyBeat"
        === toExp (everyBeat :: Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "apply function every nth beat",
      "everyBeatShift"
        === toExp (everyBeatShift :: Zwirn Time -> Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> (a -> a) -> a -> a"
        --| "apply function every nth beat, shifted in time"
    ]

cordFunctions :: Map.Map Text AnnotatedExpression
cordFunctions =
  Map.unions
    [ "pick"
        === toExp (pick :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "pick a certain layer of a cord using an index statring from 0. wraps around if the depth is exceeded",
      "inhabit"
        === toExp (inhabit :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "",
      "select"
        === toExp (select :: Zwirn Double -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "select a certain layer of a cord using a number between 0 and 1",
      "insert"
        === toExp (C.insert :: Zwirn Int -> Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a -> a"
        --| "insert into a specific layer of a cord",
      "push"
        === toExp (C.push :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "a -> a -> a"
        --| "push on top of a cord",
      "(&)"
        === toExp (C.concat :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "a -> a -> a"
        --| "concat two cords",
      "concat"
        === toExp (C.concat :: Zwirn Expression -> Zwirn Expression -> Zwirn Expression)
        <:: "a -> a -> a"
        --| "concat two cords",
      "pop"
        === toExp (C.pop :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "remove the top value of a cord",
      "remove"
        === toExp (remove :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "remove a specific layer of a cord",
      "filter"
        === toExp (C.filter :: Zwirn (Zwirn Expression -> Zwirn Bool) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> Number) -> a -> a"
        --| "filter with a predicate",
      "take"
        === toExp (C.take :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "take the first n items of a cord",
      "drop"
        === toExp (C.drop :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "drop the first n items of a cord",
      "replicate"
        === toExp (C.replicate :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "layer the same item n times",
      "superimpose"
        === toExp (superimpose :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> a) -> a -> a"
        --| "```superimpose f x = [(f x), x]```",
      "ghostWith"
        === toExp (ghostWith :: Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> (a -> a) -> a -> a"
        --| "```ghostWith n f x = [(shift (n |* 1.5) $ f x), (shift (n |* 2.5) $ f x), x]```",
      "arp"
        === toExp (arp :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "arpeggiate",
      "reverse"
        === toExp (C.reverse :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "reverse order of cord",
      "invert"
        === toExp (C.invert :: Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number"
        --| "chord inversion",
      "rotate"
        === toExp (C.rotate :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> a -> a"
        --| "cord rotation",
      "expand"
        === toExp (C.expand :: Zwirn Int -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> Number"
        --| "cord expansion",
      "open"
        === toExp (C.open :: Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number"
        --| "open cord",
      "cat"
        === toExp (cordcat :: Zwirn Expression -> Zwirn Expression)
        <:: "a -> a"
        --| "```cat [x, y, .. z] == [x y .. z]```",
      "timerun"
        === toExp (timerun :: Zwirn Time -> Zwirn Int)
        <:: "Number -> Number"
        --| "",
      "map"
        === toExp (cordmap :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "```map f [x, y, .. z] == [(f x), (f y), .. (f z)```]",
      "layer"
        === toExp (layer :: Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> b) -> a -> b"
        --| "```layer [f, g, .. h] x == [(f x), (g x), .. (h x)```]",
      "echoWith"
        === toExp (echoWith :: Zwirn Int -> Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> (a -> b) -> a -> b"
        --| "",
      "followWith"
        === toExp (followWith :: Zwirn Int -> Zwirn Time -> Zwirn (Zwirn Expression -> Zwirn Expression) -> Zwirn Expression -> Zwirn Expression)
        <:: "Number -> Number -> (a -> b) -> a -> b"
        --| "",
      "fold"
        === toExp (fold :: Zwirn (Zwirn Expression -> Zwirn (Zwirn Expression -> Zwirn Expression)) -> Zwirn Expression -> Zwirn Expression)
        <:: "(a -> a -> a) -> a -> a"
        --| "fold a function over a cord",
      "smooth"
        === toExp (interpol :: Zwirn Time -> Zwirn Time)
        <:: "Number -> Number"
        --| "linear interpolation of items in a cord",
      "depth"
        === toExp (depth :: Zwirn Expression -> Zwirn Int)
        <:: "a -> Number"
        --| "the depth of a cord",
      "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",
      "pI"
        === toExp ((\t -> fmap toExp . singleton t) :: Zwirn Text -> Zwirn Int -> Zwirn Expression)
        <:: "Text -> Number -> Map"
        --| "integer 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 -> (a -> a) -> 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",
      "juxBy"
        === toExp (juxBy :: Zwirn Expression -> Zwirn (Zwirn ExpressionMap -> Zwirn ExpressionMap) -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> (Map -> Map) -> Map -> Map"
        --| "thanks yaxu",
      "jux"
        === toExp (jux :: Zwirn (Zwirn ExpressionMap -> Zwirn ExpressionMap) -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "(Map -> Map) -> Map -> Map"
        --| "thanks yaxu",
      "echo"
        === toExp (echo :: Zwirn Int -> Zwirn Time -> Zwirn Expression -> Zwirn ExpressionMap -> Zwirn ExpressionMap)
        <:: "Number -> Number -> Number -> Map -> Map"
        --| "",
      "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"
        --| "",
      "param"
        === toExp paramName
        <:: "(a -> Map) -> Text"
        --| "given a parameter function, gives back the name of the parameter as text"
    ]

streamFunctions :: Stream -> Map.Map Text AnnotatedExpression
streamFunctions str =
  Map.unions
    [ "replace"
        === toExp (replace str)
        <:: "Id a => a -> Map -> Action"
        --| "replace the channel running with given id",
      "target"
        === toExp target
        <:: "Id a => Text -> a -> Map"
        --| "specify a specific target",
      "($:)"
        === toExp (replace str)
        <:: "Id a => a -> Map -> Action"
        --| "replace the channel running with given id",
      "replaceAction"
        === toExp (replaceAction str)
        <:: "Id a => a -> Action -> Action"
        --| "replace the channel running with given id",
      "($!)"
        === toExp (replaceAction str)
        <:: "Id a => a -> Action -> Action"
        --| "replace the channel running with given id",
      "replaceBus"
        === toExp (replaceBus str)
        <:: "Id a => a -> Number -> Action"
        --| "replace the bus running with given id",
      "(&:)"
        === toExp (replaceBus str)
        <:: "Id a => a -> Number -> Action"
        --| "replace the bus running with given id",
      "fx"
        === toExp (fx str)
        <:: "Id a => a -> (Map -> Map) -> Action"
        --| "apply the function to channel with given id",
      "(#!)"
        === toExp (fx str)
        <:: "Id a => a -> (Map -> Map) -> Action"
        --| "replace the bus running with given id",
      "all"
        === toExp allID
        <:: "Text"
        --| "special identifier to apply effects to all channels",
      "none"
        === toExp noneID
        <:: "Text"
        --| "special identifier to remove effects from all channels",
      "tempo"
        === toExp tempo
        <:: "Number"
        --| "current tempo in bpm",
      "bpc"
        === toExp bpc
        <:: "Number"
        --| "current beats per cycle",
      "hush"
        === toExp (hush str)
        <:: "Action"
        --| "hush all channels",
      "once"
        === toExp (once str)
        <:: "Map -> Action"
        --| "play one cycle of the given zwirn",
      "tonce"
        === toExp (tonce str)
        <:: "Text -> Map -> Action"
        --| "play one cycle of the given zwirn on the given target",
      "mute"
        === toExp (mute str)
        <:: "Id a => a -> Action"
        --| "mute channel with given id",
      "unmute"
        === toExp (unmute str)
        <:: "Id a => a -> Action"
        --| "unmute channel with given id",
      "toggle"
        === toExp (toggle str)
        <:: "Id a => a -> Action"
        --| "toggle channel with given id",
      "solo"
        === toExp (solo str)
        <:: "Id a => a -> Action"
        --| "solo channel with given id",
      "unsolo"
        === toExp (unsolo str)
        <:: "Id a => a -> Action"
        --| "unsolo channel with given id",
      "togglesolo"
        === toExp (togglesolo str)
        <:: "Id a => a -> Action"
        --| "toggle solo channel with given id",
      "bpm"
        === toExp (bpm str)
        <:: "Number -> Action"
        --| "set the current bpm (beats per minute)",
      "cps"
        === toExp (cps str)
        <:: "Number -> Action"
        --| "set the current cps (cycles per second)",
      "resetcycles"
        === toExp (resetcycles str)
        <:: "Action"
        --| "resets the cycle count to 0",
      "setcycle"
        === toExp (setcycle str)
        <:: "Number -> Action"
        --| "set the current cycle to specific point in time",
      "disablelink"
        === toExp (disablelink str)
        <:: "Action"
        --| "disable ableton link",
      "enablelink"
        === toExp (enablelink str)
        <:: "Action"
        --| "enable ableton link",
      "in"
        === toExp (execIn' str)
        <:: "Number -> Action -> Action"
        --| "start an action in a given amount of seconds",
      "inMod"
        === toExp (execMod str)
        <:: "Number -> Action -> Action"
        --| "start an action in a given amount of seconds",
      "transitionmap"
        === toExp (transition str)
        <:: "Id a => a -> (Number -> Map -> Map) -> Action"
        --| "",
      "transition"
        === toExp (transition' str)
        <:: "Id a => a -> Number -> b -> b -> (Map -> b -> Map) -> Action"
        --| ""
    ]