packages feed

disco-0.2: src/Disco/Doc.hs

-- SPDX-License-Identifier: BSD-3-Clause

-- |
-- Module      :  Disco.Doc
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- Built-in documentation.
module Disco.Doc (
  DocKey (..),
  RefType (..),
  Reference (..),
  mkRef,
  mkIntro,
  docMap,
) where

import Data.Map (Map)
import qualified Data.Map as M

import Disco.Syntax.Operators
import Disco.Syntax.Prims
import Disco.Util ((==>))

-- | Lookup keys for documentation.
data DocKey where
  PrimKey :: Prim -> DocKey
  OtherKey :: String -> DocKey
  deriving (Eq, Ord, Show)

-- | An enumeration of different types of documentation references.
data RefType where
  -- | A reference to the Gentle Introduction (https://disco-lang.readthedocs.io/en/latest/introduction/index.html)
  Intro :: RefType
  -- | A reference to the Language Reference (https://disco-lang.readthedocs.io/en/latest/reference/index.html)
  Ref :: RefType
  -- | An arbitrary free-form URL
  URL :: RefType
  deriving (Eq, Ord, Show, Read, Bounded, Enum)

-- | A reference for further reading.
data Reference = Reference {refType :: RefType, ref :: String}
  deriving (Eq, Ord, Show)

mkRef :: String -> Reference
mkRef = Reference Ref

mkIntro :: String -> Reference
mkIntro = Reference Intro

-- | A map storing documentation for various things that can be looked
--   up with :doc.  Each key is mapped to a short descriptive string,
--   plus references for further reading.
docMap :: Map DocKey (String, [Reference])
docMap =
  M.fromList
    [ PrimKey (PrimUOp Neg)
        ==> "Arithmetic negation."
        ==> []
    , PrimKey (PrimBOp Add)
        ==> "The sum of two numbers, types, or graphs."
        ==> [mkIntro "arithmetic", mkRef "addition"]
    , PrimKey (PrimBOp Sub)
        ==> "The difference of two numbers."
        ==> [mkIntro "arithmetic", mkRef "subtraction"]
    , PrimKey (PrimBOp SSub)
        ==> "The difference of two numbers, with a lower bound of 0."
        ==> [mkIntro "arithmetic", mkRef "subtraction", mkRef "symbols"]
    , PrimKey (PrimBOp Mul)
        ==> "The product of two numbers, types, or graphs."
        ==> [mkIntro "arithmetic", mkRef "multiplication"]
    , PrimKey (PrimBOp Div)
        ==> "Divide two numbers."
        ==> [mkIntro "arithmetic", mkRef "division"]
    , PrimKey (PrimBOp IDiv)
        ==> "The integer quotient of two numbers, rounded down."
        ==> [mkIntro "arithmetic", mkRef "integerdiv"]
    , PrimKey (PrimBOp Mod)
        ==> "a mod b is the remainder when a is divided by b."
        ==> [mkRef "mod"]
    , PrimKey (PrimBOp Exp)
        ==> "Exponentiation.  a ^ b is a raised to the b power."
        ==> [mkIntro "arithmetic", mkRef "exponentiation"]
    , PrimKey (PrimUOp Fact)
        ==> "n! computes the factorial of n, that is, 1 * 2 * ... * n."
        ==> [mkRef "factorial"]
    , PrimKey PrimFloor
        ==> "floor(x) is the largest integer which is <= x."
        ==> [mkIntro "arithmetic", mkRef "round", mkRef "symbols"]
    , PrimKey PrimCeil
        ==> "ceiling(x) is the smallest integer which is >= x."
        ==> [mkIntro "arithmetic", mkRef "round", mkRef "symbols"]
    , PrimKey PrimAbs
        ==> "abs(x) is the absolute value of x."
        ==> [mkIntro "arithmetic", mkRef "abs"]
    , PrimKey PrimMin
        ==> "min(x,y) is the minimum of x and y, i.e. whichever is smaller."
        ==> [mkRef "compare"]
    , PrimKey PrimMax
        ==> "max(x,y) is the maximum of x and y, i.e. whichever is larger."
        ==> [mkRef "compare"]
    , PrimKey (PrimUOp Not)
        ==> "Logical negation: not(T) = F and not(F) = T."
        ==> [mkRef "logic-ops", mkRef "symbols"]
    , PrimKey (PrimBOp And)
        ==> "Logical conjunction (and): T /\\ T = T; otherwise x /\\ y = F."
        ==> [mkRef "logic-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Or)
        ==> "Logical disjunction (or): F \\/ F = F; otherwise x \\/ y = T."
        ==> [mkRef "logic-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Impl)
        ==> "Logical implication (implies): T -> F = F; otherwise x -> y = T."
        ==> [mkRef "logic-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Iff)
        ==> "Biconditional (if and only if)."
        ==> [mkRef "logic-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Eq)
        ==> "Equality test.  x == y is T if x and y are equal."
        ==> [mkRef "compare"]
    , PrimKey (PrimBOp Neq)
        ==> "Inequality test.  x /= y is T if x and y are unequal."
        ==> [mkRef "compare", mkRef "symbols"]
    , PrimKey (PrimBOp Lt)
        ==> "Less-than test. x < y is T if x is less than (but not equal to) y."
        ==> [mkRef "compare"]
    , PrimKey (PrimBOp Gt)
        ==> "Greater-than test. x > y is T if x is greater than (but not equal to) y."
        ==> [mkRef "compare"]
    , PrimKey (PrimBOp Leq)
        ==> "Less-than-or-equal test. x <= y is T if x is less than or equal to y."
        ==> [mkRef "compare", mkRef "symbols"]
    , PrimKey (PrimBOp Geq)
        ==> "Greater-than-or-equal test. x >= y is T if x is greater than or equal to y."
        ==> [mkRef "compare", mkRef "symbols"]
    , PrimKey (PrimBOp CartProd)
        ==> "Cartesian product, i.e. the collection of all pairs.  Also works on bags and sets."
        ==> [mkRef "cp", mkRef "symbols"]
    , PrimKey PrimPower
        ==> "Power set, i.e. the set of all subsets.  Also works on bags."
        ==> [mkRef "power"]
    , PrimKey (PrimBOp Union)
        ==> "Union of two sets (or bags)."
        ==> [mkRef "set-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Inter)
        ==> "Intersection of two sets (or bags)."
        ==> [mkRef "set-ops", mkRef "symbols"]
    , PrimKey (PrimBOp Diff)
        ==> "Difference of two sets (or bags)."
        ==> [mkRef "set-ops"]
    , OtherKey "N" ==> docN
    , OtherKey "ℕ" ==> docN
    , OtherKey "Nat" ==> docN
    , OtherKey "Natural" ==> docN
    , OtherKey "Z" ==> docZ
    , OtherKey "ℤ" ==> docZ
    , OtherKey "Int" ==> docZ
    , OtherKey "Integer" ==> docZ
    , OtherKey "F" ==> docF
    , OtherKey "𝔽" ==> docF
    , OtherKey "Frac" ==> docF
    , OtherKey "Fractional" ==> docF
    , OtherKey "Q" ==> docQ
    , OtherKey "ℚ" ==> docQ
    , OtherKey "Rational" ==> docQ
    , OtherKey "Bool" ==> docB
    , OtherKey "Boolean" ==> docB
    , OtherKey "Unit"
        ==> "The unit type, i.e. a type with only a single value."
        ==> [mkRef "unit", mkRef "symbols"]
    , OtherKey "Prop"
        ==> "The type of propositions."
        ==> [mkRef "prop"]
    , OtherKey "List"
        ==> "List(T) is the type of lists whose elements have type T."
        ==> [mkRef "list", mkRef "list-lib"]
    , OtherKey "Bag"
        ==> "Bag(T) is the type of bags (i.e. sets with multiplicity) whose elements have type T."
        ==> [mkRef "bag", mkRef "symbols"]
    , OtherKey "Set"
        ==> "Set(T) is the type of finite sets whose elements have type T."
        ==> [mkRef "set", mkRef "symbols"]
    , OtherKey "|~|"
        ==> "Absolute value, or the size of a collection."
        ==> [mkIntro "arithmetic", mkRef "size"]
    , OtherKey "{?"
        ==> "{? ... ?} is a case expression, for choosing a result based on conditions."
        ==> [mkRef "case"]
    , OtherKey "λ"
        ==> "λ (aka lambda, alternatively `\\`) introduces an anonymous function."
        ==> [mkRef "anonymous-func", mkRef "symbols"]
    , OtherKey "#"
        ==> "The # character is used to denote the cardinality of an element in a bag."
        ==> [mkRef "bag"]
    ]
 where
  docN = ("The type of natural numbers: 0, 1, 2, ...", refsN)
  refsN = [mkIntro "types", mkRef "natural", mkRef "symbols"]

  docZ = ("The type of integers: ..., -2, -1, 0, 1, 2, ...", refsZ)
  refsZ = [mkIntro "types", mkRef "integer", mkRef "symbols"]

  docF = ("The type of fractional numbers p/q >= 0.", refsF)
  refsF = [mkIntro "types", mkRef "fraction", mkRef "symbols"]

  docQ = ("The type of rational numbers p/q.", refsQ)
  refsQ = [mkIntro "types", mkRef "rational", mkRef "symbols"]

  docB = ("The type of Booleans (T or F).", refsB)
  refsB = [mkRef "bool"]