-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Functional programming language for teaching discrete math. -- -- Disco is a simple functional programming language for use in teaching -- discrete math. Its syntax is designed to be close to standard -- mathematical practice. @package disco @version 0.2 -- | Some orphan Data instances. module Disco.Data instance (Data.Data.Data a, Data.Data.Data b) => Data.Data.Data (Unbound.Generics.LocallyNameless.Bind.Bind a b) instance Data.Data.Data t => Data.Data.Data (Unbound.Generics.LocallyNameless.Embed.Embed t) instance (Data.Data.Data a, Data.Data.Data b) => Data.Data.Data (Unbound.Generics.LocallyNameless.Rebind.Rebind a b) instance Data.Data.Data a => Data.Data.Data (Unbound.Generics.LocallyNameless.Name.Name a) -- | Polysemy effect for integer counter. module Disco.Effects.Counter data Counter m a -- | Return the next integer in sequence. [Next] :: Counter m Integer -- | Return the next integer in sequence. next :: forall r_arCG. Member Counter r_arCG => Sem r_arCG Integer -- | Dispatch a counter effect, starting the counter from the given -- Integer. runCounter' :: Integer -> Sem (Counter ': r) a -> Sem r a -- | Dispatch a counter effect, starting the counter from zero. runCounter :: Sem (Counter ': r) a -> Sem r a -- | Utility functions for input effect. module Disco.Effects.Input -- | Run an input effect in terms of an ambient state effect. inputToState :: forall s r a. Member (State s) r => Sem (Input s ': r) a -> Sem r a -- | Use a function to (contravariantly) transform the input value in an -- input effect. mapInput :: forall s t r a. Member (Input s) r => (s -> t) -> Sem (Input t ': r) a -> Sem r a -- | Utility functions for state effect. module Disco.Effects.State -- | Use a lens to zoom into a component of a state. zoom :: forall s a r c. Member (State s) r => Lens' s a -> Sem (State a ': r) c -> Sem r c use :: Member (State s) r => Getter s a -> Sem r a (%=) :: Member (State s) r => Lens' s a -> (a -> a) -> Sem r () infix 4 %= (.=) :: Member (State s) r => Lens' s a -> a -> Sem r () infix 4 .= -- | Polysemy effect for a memory store with integer keys. module Disco.Effects.Store data Store v m a [ClearStore] :: Store v m () [New] :: v -> Store v m Int [LookupStore] :: Int -> Store v m (Maybe v) [InsertStore] :: Int -> v -> Store v m () [MapStore] :: (v -> v) -> Store v m () [AssocsStore] :: Store v m [(Int, v)] [KeepKeys] :: IntSet -> Store v m () keepKeys :: forall v_auzq r_auFO. Member (Store v_auzq) r_auFO => IntSet -> Sem r_auFO () assocsStore :: forall v_auzo r_auFN. Member (Store v_auzo) r_auFN => Sem r_auFN [(Int, v_auzo)] mapStore :: forall v_auzm r_auFL. Member (Store v_auzm) r_auFL => (v_auzm -> v_auzm) -> Sem r_auFL () insertStore :: forall v_auzk r_auFI. Member (Store v_auzk) r_auFI => Int -> v_auzk -> Sem r_auFI () lookupStore :: forall v_auzi r_auFG. Member (Store v_auzi) r_auFG => Int -> Sem r_auFG (Maybe v_auzi) new :: forall v_auzg r_auFE. Member (Store v_auzg) r_auFE => v_auzg -> Sem r_auFE Int clearStore :: forall v_auze r_auFD. Member (Store v_auze) r_auFD => Sem r_auFD () -- | Dispatch a store effect. runStore :: forall v r a. Sem (Store v ': r) a -> Sem r a -- | Meaningful types and functions for describing combinations of -- different possible options. module Disco.Exhaustiveness.Possibilities data Possibilities a retSingle :: Monad m => a -> m (Possibilities a) -- | List all possible paths through the list of Possibilites -- -- Ex. > allCombinations [ Possibilities [1] , Possibilities [2,3] , -- Possibilities [4] , Possibilities [5,6,7] ] === Possibilities -- {getPossibilities = [[1,2,4,5] ,[1,2,4,6] ,[1,2,4,7] ,[1,3,4,5] -- ,[1,3,4,6] ,[1,3,4,7] ]} -- -- 2 5 1 4 --6 / 3 7 -- -- If any any of the Possibilities is empty, an empty Possibility is -- returned -- -- In other words, this lists all elements of the cartesian product of -- multiple sets allCombinations :: [Possibilities a] -> Possibilities [a] anyOf :: [Possibilities a] -> Possibilities a none :: Possibilities a -> Bool getPossibilities :: Possibilities a -> [a] instance GHC.Base.Applicative Disco.Exhaustiveness.Possibilities.Possibilities instance GHC.Base.Monoid (Disco.Exhaustiveness.Possibilities.Possibilities a) instance GHC.Base.Semigroup (Disco.Exhaustiveness.Possibilities.Possibilities a) instance GHC.Base.Functor Disco.Exhaustiveness.Possibilities.Possibilities instance GHC.Classes.Ord a => GHC.Classes.Ord (Disco.Exhaustiveness.Possibilities.Possibilities a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Disco.Exhaustiveness.Possibilities.Possibilities a) instance GHC.Show.Show a => GHC.Show.Show (Disco.Exhaustiveness.Possibilities.Possibilities a) -- | Optional extensions to the disco language. module Disco.Extensions -- | Enumeration of optional language extensions. data Ext -- | Allow primitives, i.e. $prim Primitives :: Ext -- | Don't automatically import standard library modules NoStdLib :: Ext -- | Allow randomness. This is not implemented yet. Randomness :: Ext type ExtSet = Set Ext -- | The default set of language extensions (currently, the empty set). defaultExts :: ExtSet -- | A set of all possible language extensions, provided for convenience. allExts :: ExtSet -- | All possible language extensions in the form of a list. allExtsList :: [Ext] -- | Add an extension to an extension set. addExtension :: Ext -> ExtSet -> ExtSet instance GHC.Enum.Bounded Disco.Extensions.Ext instance GHC.Enum.Enum Disco.Extensions.Ext instance GHC.Read.Read Disco.Extensions.Ext instance GHC.Show.Show Disco.Extensions.Ext instance GHC.Classes.Ord Disco.Extensions.Ext instance GHC.Classes.Eq Disco.Extensions.Ext -- | XXX module Disco.Report data Report RTxt :: String -> Report RSeq :: [Report] -> Report RVSeq :: [Report] -> Report RList :: [Report] -> Report RNest :: Report -> Report text :: String -> Report hcat :: [Report] -> Report hsep :: [Report] -> Report vcat :: [Report] -> Report vsep :: [Report] -> Report list :: [Report] -> Report nest :: Report -> Report instance GHC.Show.Show Disco.Report.Report -- | Unary and binary operators along with information like precedence, -- fixity, and concrete syntax. module Disco.Syntax.Operators -- | Unary operators. data UOp -- | Arithmetic negation (-) Neg :: UOp -- | Logical negation (not) Not :: UOp -- | Factorial (!) Fact :: UOp -- | Binary operators. data BOp -- | Addition (+) Add :: BOp -- | Subtraction (-) Sub :: BOp -- | Saturating Subtraction (.- / ∸) SSub :: BOp -- | Multiplication (*) Mul :: BOp -- | Division (/) Div :: BOp -- | Exponentiation (^) Exp :: BOp -- | Integer division (//) IDiv :: BOp -- | Equality test (==) Eq :: BOp -- | Not-equal (/=) Neq :: BOp -- | Less than (<) Lt :: BOp -- | Greater than (>) Gt :: BOp -- | Less than or equal (<=) Leq :: BOp -- | Greater than or equal (>=) Geq :: BOp -- | Logical and (&& / and) And :: BOp -- | Logical or (|| / or) Or :: BOp -- | Logical implies (-> / implies) Impl :: BOp -- | Logical biconditional (- / iff) Iff :: BOp -- | Modulo (mod) Mod :: BOp -- | Divisibility test (|) Divides :: BOp -- | Binomial and multinomial coefficients (choose) Choose :: BOp -- | List cons (::) Cons :: BOp -- | Cartesian product of sets (** / ⨯) CartProd :: BOp -- | Union of two sets (union / ∪) Union :: BOp -- | Intersection of two sets (intersect / ∩) Inter :: BOp -- | Difference between two sets (@@) Diff :: BOp -- | Element test (∈) Elem :: BOp -- | Subset test (⊆) Subset :: BOp -- | Make a binary boolean operator into a testable proposition Should :: BOp -> BOp -- | Type operators. data TyOp -- | List all values of a type Enumerate :: TyOp -- | Count how many values there are of a type Count :: TyOp -- | Fixities of unary operators (either pre- or postfix). data UFixity -- | Unary prefix. Pre :: UFixity -- | Unary postfix. Post :: UFixity -- | Fixity/associativity of infix binary operators (either left, right, or -- non-associative). data BFixity -- | Left-associative infix. InL :: BFixity -- | Right-associative infix. InR :: BFixity -- | Infix. In :: BFixity -- | Operators together with their fixity. data OpFixity UOpF :: UFixity -> UOp -> OpFixity BOpF :: BFixity -> BOp -> OpFixity -- | An OpInfo record contains information about an operator, such -- as the operator itself, its fixity, a list of concrete syntax -- representations, and a numeric precedence level. data OpInfo OpInfo :: OpFixity -> [String] -> Int -> OpInfo [opFixity] :: OpInfo -> OpFixity [opSyns] :: OpInfo -> [String] [opPrec] :: OpInfo -> Int -- | The opTable lists all the operators in the language, in order -- of precedence (highest precedence first). Operators in the same list -- have the same precedence. This table is used by both the parser and -- the pretty-printer. opTable :: [[OpInfo]] -- | A map from all unary operators to their associated OpInfo -- records. uopMap :: Map UOp OpInfo -- | A map from all binary operators to their associatied OpInfo -- records. bopMap :: Map BOp OpInfo opNames :: [String] -- | A convenient function for looking up the precedence of a unary -- operator. uPrec :: UOp -> Int -- | A convenient function for looking up the precedence of a binary -- operator. bPrec :: BOp -> Int -- | Look up the "fixity" (i.e. associativity) of a binary operator. assoc :: BOp -> BFixity -- | The precedence level of function application (higher than any other -- precedence level). funPrec :: Int instance Unbound.Generics.LocallyNameless.Subst.Subst t Disco.Syntax.Operators.UOp instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Syntax.Operators.UOp instance Data.Data.Data Disco.Syntax.Operators.UOp instance GHC.Generics.Generic Disco.Syntax.Operators.UOp instance GHC.Classes.Ord Disco.Syntax.Operators.UOp instance GHC.Classes.Eq Disco.Syntax.Operators.UOp instance GHC.Read.Read Disco.Syntax.Operators.UOp instance GHC.Show.Show Disco.Syntax.Operators.UOp instance Unbound.Generics.LocallyNameless.Subst.Subst t Disco.Syntax.Operators.BOp instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Syntax.Operators.BOp instance Data.Data.Data Disco.Syntax.Operators.BOp instance GHC.Generics.Generic Disco.Syntax.Operators.BOp instance GHC.Classes.Ord Disco.Syntax.Operators.BOp instance GHC.Classes.Eq Disco.Syntax.Operators.BOp instance GHC.Read.Read Disco.Syntax.Operators.BOp instance GHC.Show.Show Disco.Syntax.Operators.BOp instance Unbound.Generics.LocallyNameless.Subst.Subst t Disco.Syntax.Operators.TyOp instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Syntax.Operators.TyOp instance Data.Data.Data Disco.Syntax.Operators.TyOp instance GHC.Generics.Generic Disco.Syntax.Operators.TyOp instance GHC.Classes.Ord Disco.Syntax.Operators.TyOp instance GHC.Classes.Eq Disco.Syntax.Operators.TyOp instance GHC.Show.Show Disco.Syntax.Operators.TyOp instance GHC.Generics.Generic Disco.Syntax.Operators.UFixity instance GHC.Show.Show Disco.Syntax.Operators.UFixity instance GHC.Enum.Bounded Disco.Syntax.Operators.UFixity instance GHC.Enum.Enum Disco.Syntax.Operators.UFixity instance GHC.Classes.Ord Disco.Syntax.Operators.UFixity instance GHC.Classes.Eq Disco.Syntax.Operators.UFixity instance GHC.Generics.Generic Disco.Syntax.Operators.BFixity instance GHC.Show.Show Disco.Syntax.Operators.BFixity instance GHC.Enum.Bounded Disco.Syntax.Operators.BFixity instance GHC.Enum.Enum Disco.Syntax.Operators.BFixity instance GHC.Classes.Ord Disco.Syntax.Operators.BFixity instance GHC.Classes.Eq Disco.Syntax.Operators.BFixity instance GHC.Generics.Generic Disco.Syntax.Operators.OpFixity instance GHC.Show.Show Disco.Syntax.Operators.OpFixity instance GHC.Classes.Eq Disco.Syntax.Operators.OpFixity instance GHC.Show.Show Disco.Syntax.Operators.OpInfo -- | Precedence and associativity for pretty-printing. module Disco.Pretty.Prec type Prec = Int data PA PA :: Prec -> BFixity -> PA lowerPrec :: PA -> PA -> Bool initPA :: PA ascrPA :: PA funPA :: PA rPA :: Int -> PA tarrPA :: PA taddPA :: PA tmulPA :: PA tfunPA :: PA ugetPA :: UOp -> PA getPA :: BOp -> PA instance GHC.Classes.Eq Disco.Pretty.Prec.PA instance GHC.Show.Show Disco.Pretty.Prec.PA -- | Adapter DSL on top of Text.PrettyPrint for Applicative -- pretty-printing. module Disco.Pretty.DSL vcat :: Applicative f => [f (Doc ann)] -> f (Doc ann) hcat :: Applicative f => [f (Doc ann)] -> f (Doc ann) hsep :: Applicative f => [f (Doc ann)] -> f (Doc ann) parens :: Functor f => f (Doc ann) -> f (Doc ann) brackets :: Functor f => f (Doc ann) -> f (Doc ann) braces :: Functor f => f (Doc ann) -> f (Doc ann) bag :: Applicative f => f (Doc ann) -> f (Doc ann) quotes :: Functor f => f (Doc ann) -> f (Doc ann) doubleQuotes :: Functor f => f (Doc ann) -> f (Doc ann) text :: Applicative m => String -> m (Doc ann) integer :: Applicative m => Integer -> m (Doc ann) nest :: Functor f => Int -> f (Doc ann) -> f (Doc ann) indent :: Functor f => Int -> f (Doc ann) -> f (Doc ann) hang :: Applicative f => f (Doc ann) -> Int -> f (Doc ann) -> f (Doc ann) empty :: Applicative m => m (Doc ann) (<+>) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann) (<>) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann) ($+$) :: Applicative f => f (Doc ann) -> f (Doc ann) -> f (Doc ann) punctuate :: Applicative f => f (Doc ann) -> [f (Doc ann)] -> f [f (Doc ann)] intercalate :: Monad f => f (Doc ann) -> [f (Doc ann)] -> f (Doc ann) bulletList :: Applicative f => f (Doc ann) -> [f (Doc ann)] -> f (Doc ann) renderDoc :: Sem (Reader PA ': r) (Doc ann) -> Sem r String renderDoc' :: Doc ann -> String instance Data.String.IsString (Polysemy.Internal.Sem r (Prettyprinter.Internal.Doc ann)) -- | Concrete syntax for the prims (i.e. built-in constants) supported by -- the language. module Disco.Syntax.Prims -- | Primitives, i.e. built-in constants. data Prim -- | Unary operator [PrimUOp] :: UOp -> Prim -- | Binary operator [PrimBOp] :: BOp -> Prim -- | Left injection into a sum type. [PrimLeft] :: Prim -- | Right injection into a sum type. [PrimRight] :: Prim -- | Integer square root (sqrt) [PrimSqrt] :: Prim -- | Floor of fractional type (floor) [PrimFloor] :: Prim -- | Ceiling of fractional type (ceiling) [PrimCeil] :: Prim -- | Absolute value (abs) [PrimAbs] :: Prim -- | Min [PrimMin] :: Prim -- | Max [PrimMax] :: Prim -- | Power set (XXX or bag?) [PrimPower] :: Prim -- | Container -> list conversion [PrimList] :: Prim -- | Container -> bag conversion [PrimBag] :: Prim -- | Container -> set conversion [PrimSet] :: Prim -- | bag -> set of counts conversion [PrimB2C] :: Prim -- | set of counts -> bag conversion [PrimC2B] :: Prim -- | unsafe set of counts -> bag conversion that assumes all distinct [PrimUC2B] :: Prim -- | Map k v -> Set (k × v) [PrimMapToSet] :: Prim -- | Set (k × v) -> Map k v [PrimSetToMap] :: Prim -- | Get Adjacency list of Graph [PrimSummary] :: Prim -- | Construct a graph Vertex [PrimVertex] :: Prim -- | Empty graph [PrimEmptyGraph] :: Prim -- | Overlay two Graphs [PrimOverlay] :: Prim -- | Connect Graph to another with directed edges [PrimConnect] :: Prim -- | Insert into map [PrimInsert] :: Prim -- | Get value associated with key in map [PrimLookup] :: Prim -- | Each operation for containers [PrimEach] :: Prim -- | Reduce operation for containers [PrimReduce] :: Prim -- | Filter operation for containers [PrimFilter] :: Prim -- | Monadic join for containers [PrimJoin] :: Prim -- | Generic merge operation for bags/sets [PrimMerge] :: Prim -- | Efficient primality test [PrimIsPrime] :: Prim -- | Factorization [PrimFactor] :: Prim -- | Turn a rational into a pair (num, denom) [PrimFrac] :: Prim -- | Crash [PrimCrash] :: Prim -- |
-- [x, y, z .. e] --[PrimUntil] :: Prim -- | Test whether a proposition holds [PrimHolds] :: Prim -- | Lookup OEIS sequence [PrimLookupSeq] :: Prim -- | Extend OEIS sequence [PrimExtendSeq] :: Prim -- | Generates a pseudorandom number generator [PrimSeed] :: Prim -- | Given a range and a generator, generates random number [PrimRandom] :: Prim -- | An info record for a single primitive name, containing the primitive -- itself, its concrete syntax, and whether it is "exposed", i.e. -- available to be used in the surface syntax of the basic language. -- Unexposed prims can only be referenced by enabling the Primitives -- language extension and prefixing their name by $. data PrimInfo PrimInfo :: Prim -> String -> Bool -> PrimInfo [thePrim] :: PrimInfo -> Prim [primSyntax] :: PrimInfo -> String [primExposed] :: PrimInfo -> Bool -- | A table containing a PrimInfo record for every non-operator -- Prim recognized by the language. primTable :: [PrimInfo] -- | Find any exposed prims with the given name. toPrim :: String -> [Prim] -- | A convenient map from each Prim to its info record. primMap :: Map Prim PrimInfo instance Data.Data.Data Disco.Syntax.Prims.Prim instance Unbound.Generics.LocallyNameless.Subst.Subst t Disco.Syntax.Prims.Prim instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Syntax.Prims.Prim instance GHC.Generics.Generic Disco.Syntax.Prims.Prim instance GHC.Classes.Ord Disco.Syntax.Prims.Prim instance GHC.Classes.Eq Disco.Syntax.Prims.Prim instance GHC.Read.Read Disco.Syntax.Prims.Prim instance GHC.Show.Show Disco.Syntax.Prims.Prim -- | Miscellaneous utilities. module Disco.Util -- | A synonym for pairing which makes convenient syntax for constructing -- literal maps via M.fromList. (==>) :: a -> b -> (a, b) infixr 1 ==> -- | Flipped variant of map. for :: [a] -> (a -> b) -> [b] -- | A variant of Map indexing that throws a custom error message -- in case the key is not found, to help with debugging. (!) :: (Show k, Ord k) => Map k v -> k -> v -- | Find the maximum of a list of positive numbers, yielding 0 in the case -- of an empty list. maximum0 :: (Num a, Ord a) => [a] -> a -- | A variant of filter that returns a Maybe (NonEmpty a) -- instead of a regular list. filterNE :: (a -> Bool) -> NonEmpty a -> Maybe (NonEmpty a) -- | A variant of partition that returns Maybe (NonEmpty -- a)s instead of regular lists. partitionNE :: (a -> Bool) -> NonEmpty a -> (Maybe (NonEmpty a), Maybe (NonEmpty a)) -- | A variant of partitionEithers for nonempty lists. If the -- result is Left, it means all the inputs were Left. If the result is -- Right, we definitely have some Rights, and possibly some Lefts as -- well. This properly encodes the fact that at least one result list -- must be nonempty. partitionEithersNE :: NonEmpty (Either a b) -> Either (NonEmpty a) ([a], NonEmpty b) -- | Iterate a function until finding the first value that satisfies the -- given predicate. iterUntil f p is equivalent to head . -- filter p . iterate f but does not trigger a partiality warning. iterUntil :: (a -> a) -> (a -> Maybe b) -> a -> b -- | Allow a value through only if it satisfies the given predicate. gate :: Alternative f => (a -> Bool) -> a -> f a -- | Built-in documentation. module Disco.Doc -- | Lookup keys for documentation. data DocKey [PrimKey] :: Prim -> DocKey [OtherKey] :: String -> DocKey -- | An enumeration of different types of documentation references. data RefType -- | A reference to the Gentle Introduction -- (https:/disco-lang.readthedocs.ioenlatestintroduction/index.html) [Intro] :: RefType -- | A reference to the Language Reference -- (https:/disco-lang.readthedocs.ioenlatestreference/index.html) [Ref] :: RefType -- | An arbitrary free-form URL [URL] :: RefType -- | A reference for further reading. data Reference Reference :: RefType -> String -> Reference [refType] :: Reference -> RefType [ref] :: Reference -> String mkRef :: String -> Reference mkIntro :: String -> Reference -- | 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]) instance GHC.Show.Show Disco.Doc.DocKey instance GHC.Classes.Ord Disco.Doc.DocKey instance GHC.Classes.Eq Disco.Doc.DocKey instance GHC.Enum.Enum Disco.Doc.RefType instance GHC.Enum.Bounded Disco.Doc.RefType instance GHC.Read.Read Disco.Doc.RefType instance GHC.Show.Show Disco.Doc.RefType instance GHC.Classes.Ord Disco.Doc.RefType instance GHC.Classes.Eq Disco.Doc.RefType instance GHC.Show.Show Disco.Doc.Reference instance GHC.Classes.Ord Disco.Doc.Reference instance GHC.Classes.Eq Disco.Doc.Reference -- | Polysemy effect for local fresh name generation, compatible with the -- unbound-generics library. module Disco.Effects.LFresh -- | Local fresh name generation effect. data LFresh m a [Lfresh] :: Typeable a => Name a -> LFresh m (Name a) [Avoid] :: [AnyName] -> m a -> LFresh m a [GetAvoids] :: LFresh m (Set AnyName) getAvoids :: forall r_a1ewG. Member LFresh r_a1ewG => Sem r_a1ewG (Set AnyName) avoid :: forall r_a1ewD a_a1euQ. Member LFresh r_a1ewD => [AnyName] -> Sem r_a1ewD a_a1euQ -> Sem r_a1ewD a_a1euQ lfresh :: forall r_a1ewB a_X0. (Member LFresh r_a1ewB, Typeable a_X0) => Name a_X0 -> Sem r_a1ewB (Name a_X0) -- | Dispatch an LFresh effect via a Reader effect to keep -- track of a set of in-scope names. runLFresh :: Sem (LFresh ': r) a -> Sem r a runLFresh' :: Sem (LFresh ': r) a -> Sem (Reader (Set AnyName) ': r) a -- | Open a binder, automatically freshening the names of the bound -- variables, and providing the opened pattern and term to the provided -- continuation. The bound variables are also added to the set of -- in-scope variables within in the continuation. lunbind :: (Member LFresh r, Alpha p, Alpha t) => Bind p t -> ((p, t) -> Sem r c) -> Sem r c absorbLFresh :: Member LFresh r => (LFresh (Sem r) => Sem r a) -> Sem r a data LFreshDict m LFreshDict :: (forall a. Typeable a => Name a -> m (Name a)) -> (forall a. [AnyName] -> m a -> m a) -> m (Set AnyName) -> LFreshDict m [lfresh_] :: LFreshDict m -> forall a. Typeable a => Name a -> m (Name a) [avoid_] :: LFreshDict m -> forall a. [AnyName] -> m a -> m a [getAvoids_] :: LFreshDict m -> m (Set AnyName) -- | Wrapper for a monadic action with phantom type parameter for -- reflection. Locally defined so that the instance we are going to build -- with reflection must be coherent, that is there cannot be orphans. newtype Action m s' a Action :: m a -> Action m s' a instance forall (m :: * -> *) k (s' :: k). GHC.Base.Monad m => GHC.Base.Monad (Disco.Effects.LFresh.Action m s') instance forall (m :: * -> *) k (s' :: k). GHC.Base.Applicative m => GHC.Base.Applicative (Disco.Effects.LFresh.Action m s') instance forall (m :: * -> *) k (s' :: k). GHC.Base.Functor m => GHC.Base.Functor (Disco.Effects.LFresh.Action m s') instance forall k (m :: * -> *) (s' :: k). (GHC.Base.Monad m, Data.Reflection.Reifies s' (Disco.Effects.LFresh.LFreshDict m)) => Unbound.Generics.LocallyNameless.LFresh.LFresh (Disco.Effects.LFresh.Action m s') -- | Various pretty-printing facilities for disco. module Disco.Pretty class Pretty t pretty :: (Pretty t, Members '[Reader PA, LFresh] r) => t -> Sem r (Doc ann) pretty' :: Pretty t => t -> Sem r (Doc ann) prettyStr :: Pretty t => t -> Sem r String -- | Convenience function combining setPA and mparens, since -- we often want to simultaneously indicate what the precedence and -- associativity of a term is, and optionally surround it with -- parentheses depending on the precedence and associativity of its -- parent. withPA :: Member (Reader PA) r => PA -> Sem r (Doc ann) -> Sem r (Doc ann) -- | Mark a subcomputation as pretty-printing a term on the left of an -- operator (so parentheses can be inserted appropriately, depending on -- the associativity). lt :: Member (Reader PA) r => Sem r (Doc ann) -> Sem r (Doc ann) -- | Optionally surround a pretty-printed term with parentheses, depending -- on its precedence and associativity (given as the PA argument) -- and that of its context (given by the ambient 'Reader PA' effect). mparens :: Member (Reader PA) r => PA -> Sem r (Doc ann) -> Sem r (Doc ann) -- | Locally set the precedence and associativity within a subcomputation. setPA :: Member (Reader PA) r => PA -> Sem r a -> Sem r a -- | Mark a subcomputation as pretty-printing a term on the right of an -- operator (so parentheses can be inserted appropriately, depending on -- the associativity). rt :: Member (Reader PA) r => Sem r (Doc ann) -> Sem r (Doc ann) -- | Pretty-print a rational number as a fraction. prettyRational :: Rational -> String -- | Pretty-print a rational number using its decimal expansion, in the -- format nnn.prefix[rep]..., with any repeating digits enclosed -- in square brackets. prettyDecimal :: Rational -> String -- | digitalExpansion b n d takes the numerator and denominator of -- a fraction n/d between 0 and 1, and returns a pair of (1) a list of -- digits ds, and (2) a nonnegative integer k such that -- splitAt k ds = (prefix, rep), where the infinite base-b -- expansion of n/d is 0.(prefix ++ cycle rep). For example, -- --
-- digitalExpansion 10 1 4 = ([2,5,0], 2) -- digitalExpansion 10 1 7 = ([1,4,2,8,5,7], 0) -- digitalExpansion 10 3 28 = ([1,0,7,1,4,2,8,5], 2) -- digitalExpansion 2 1 5 = ([0,0,1,1], 0) ---- -- It works by performing the standard long division algorithm, and -- looking for the first time that the remainder repeats. digitalExpansion :: Integer -> Integer -> Integer -> ([Integer], Int) findRep :: Ord a => [a] -> ([a], Int) findRep' :: Ord a => Map a Int -> Int -> [a] -> ([a], Int) -- | The abstract data type Doc ann represents pretty -- documents that have been annotated with data of type ann. -- -- More specifically, a value of type Doc represents a -- non-empty set of possible layouts of a document. The layout functions -- select one of these possibilities, taking into account things like the -- width of the output document. -- -- The annotation is an arbitrary piece of data associated with (part of) -- a document. Annotations may be used by the rendering backends in order -- to display output differently, such as -- --
-- >>> putStrLn (show (vsep ["hello", "world"])) -- hello -- world --data () => Doc ann instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty [a] instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty (GHC.Base.NonEmpty a) instance (Disco.Pretty.Pretty k, Disco.Pretty.Pretty v) => Disco.Pretty.Pretty (Data.Map.Internal.Map k v) instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty (Data.Set.Internal.Set a) instance Disco.Pretty.Pretty (Unbound.Generics.LocallyNameless.Name.Name a) instance Disco.Pretty.Pretty Disco.Syntax.Operators.TyOp instance Disco.Pretty.Pretty Disco.Syntax.Operators.UOp instance Disco.Pretty.Pretty Disco.Syntax.Operators.BOp -- | Type qualifiers and sorts. module Disco.Types.Qualifiers -- | A "qualifier" is kind of like a type class in Haskell; but unlike -- Haskell, disco users cannot define their own. Rather, there is a -- finite fixed list of qualifiers supported by disco. For example, -- QSub denotes types which support a subtraction operation. -- Each qualifier corresponds to a set of types which satisfy it (see -- hasQual and qualRules). -- -- These qualifiers generally arise from uses of various operations. For -- example, the expression \x y. x - y would be inferred to have -- a type a -> a -> a [subtractive a], that is, a function -- of type a -> a -> a where a is any type that -- supports subtraction. -- -- These qualifiers can appear in a CQual constraint; see -- Disco.Typecheck.Constraint. data Qualifier -- | Numeric, i.e. a semiring supporting + and * QNum :: Qualifier -- | Subtractive, i.e. supports - QSub :: Qualifier -- | Divisive, i.e. supports / QDiv :: Qualifier -- | Comparable, i.e. supports decidable ordering/comparison (see Note -- [QCmp]) QCmp :: Qualifier -- | Enumerable, i.e. supports ellipsis notation [x .. y] QEnum :: Qualifier -- | Boolean, i.e. supports and, or, not (Bool or Prop) QBool :: Qualifier -- | Things that do not involve Prop. QBasic :: Qualifier -- | Things for which we can derive a *Haskell* Ord instance QSimple :: Qualifier -- | A helper function that returns the appropriate qualifier for a binary -- arithmetic operation. bopQual :: BOp -> Qualifier -- | A Sort represents a set of qualifiers, and also represents a -- set of types (in general, the intersection of the sets corresponding -- to the qualifiers). type Sort = Set Qualifier -- | The special sort <math> which includes all types. topSort :: Sort instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Types.Qualifiers.Qualifier instance GHC.Generics.Generic Disco.Types.Qualifiers.Qualifier instance GHC.Classes.Ord Disco.Types.Qualifiers.Qualifier instance GHC.Classes.Eq Disco.Types.Qualifiers.Qualifier instance GHC.Show.Show Disco.Types.Qualifiers.Qualifier instance Disco.Pretty.Pretty Disco.Types.Qualifiers.Qualifier -- | A thin layer on top of graphs from the fgl package, which -- allows dealing with vertices by label instead of by integer -- Node values. module Disco.Typecheck.Graph -- | Directed graphs, with vertices labelled by a and unlabelled -- edges. data Graph a G :: Gr a () -> Map a Node -> Map Node a -> Graph a -- | Create a graph with the given set of vertices and directed edges. If -- any edges refer to vertices that are not in the given vertex set, they -- will simply be dropped. mkGraph :: (Show a, Ord a) => Set a -> Set (a, a) -> Graph a -- | Return the set of vertices (nodes) of a graph. nodes :: Graph a -> Set a -- | Return the set of directed edges of a graph. edges :: Ord a => Graph a -> Set (a, a) -- | Map a function over all the vertices of a graph. Graph is not -- a Functor instance because of the Ord constraint on -- b. map :: Ord b => (a -> b) -> Graph a -> Graph b -- | Delete a vertex. delete :: (Show a, Ord a) => a -> Graph a -> Graph a -- | The condensation of a graph is the graph of its strongly -- connected components, i.e. each strongly connected component is -- compressed to a single node, labelled by the set of vertices in the -- component. There is an edge from component A to component B in the -- condensed graph iff there is an edge from any vertex in component A to -- any vertex in component B in the original graph. condensation :: Ord a => Graph a -> Graph (Set a) -- | Get a list of the weakly connected components of a graph, providing -- the set of vertices in each. Equivalently, return the strongly -- connected components of the graph when considered as an undirected -- graph. wcc :: Ord a => Graph a -> [Set a] wccIDs :: Ord a => Graph a -> [Set (Node, a)] -- | Do a topological sort on a DAG. topsort :: Graph a -> [a] -- | A miscellaneous utility function to turn a Graph Maybe into a -- Maybe Graph: the result is Just iff all the vertices -- in the input graph are. sequenceGraph :: Ord a => Graph (Maybe a) -> Maybe (Graph a) -- | Get a list of all the successors of a given node in the graph, -- i.e. all the nodes reachable from the given node by a directed -- path. Does not include the given node itself. suc :: (Show a, Ord a) => Graph a -> a -> [a] -- | Get a list of all the predecessors of a given node in the -- graph, i.e. all the nodes from which from the given node is -- reachable by a directed path. Does not include the given node itself. pre :: (Show a, Ord a) => Graph a -> a -> [a] -- | Given a graph, return two mappings: the first maps each vertex to its -- set of successors; the second maps each vertex to its set of -- predecessors. Equivalent to -- --
-- (M.fromList *** M.fromList) . unzip . map (\a -> ((a, suc g a), (a, pre g a))) . nodes $ g ---- -- but much more efficient. cessors :: (Show a, Ord a) => Graph a -> (Map a (Set a), Map a (Set a)) instance GHC.Show.Show a => GHC.Show.Show (Disco.Typecheck.Graph.Graph a) instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty (Disco.Typecheck.Graph.Graph a) -- | The Disco.Subst module defines a generic type of substitutions -- that map variable names to values. module Disco.Subst -- | A value of type Substitution a is a substitution which maps -- some set of names (the domain, see dom) to values of -- type a. Substitutions can be applied to certain terms -- (see applySubst), replacing any free occurrences of names in -- the domain with their corresponding values. Thus, substitutions can be -- thought of as functions of type Term -> Term (for suitable -- Terms that contain names and values of the right type). -- -- Concretely, substitutions are stored using a Map. -- -- See also Disco.Types, which defines S as an alias for -- substitutions on types (the most common kind in the disco codebase). newtype Substitution a Substitution :: Map (Name a) a -> Substitution a [getSubst] :: Substitution a -> Map (Name a) a -- | The domain of a substitution is the set of names for which the -- substitution is defined. dom :: Substitution a -> Set (Name a) -- | The identity substitution, i.e. the unique substitution with an -- empty domain, which acts as the identity function on terms. idS :: Substitution a -- | Construct a singleton substitution, which maps the given name to the -- given value. (|->) :: Name a -> a -> Substitution a -- | Create a substitution from an association list of names and values. fromList :: [(Name a, a)] -> Substitution a -- | Convert a substitution into an association list. toList :: Substitution a -> [(Name a, a)] -- | Compose two substitutions. Applying s1 @@ s2 is the same as -- applying first s2, then s1; that is, semantically, -- composition of substitutions corresponds exactly to function -- composition when they are considered as functions on terms. -- -- As one would expect, composition is associative and has idS as -- its identity. (@@) :: Subst a a => Substitution a -> Substitution a -> Substitution a -- | Compose a whole container of substitutions. For example, compose -- [s1, s2, s3] = s1 @@ s2 @@ s3. compose :: (Subst a a, Foldable t) => t (Substitution a) -> Substitution a -- | Apply a substitution to a term, resulting in a new term in which any -- free variables in the domain of the substitution have been replaced by -- their corresponding values. Note this requires a Subst b a -- constraint, which intuitively means that values of type a -- contain variables of type b we can substitute for. applySubst :: Subst b a => Substitution b -> a -> a -- | Look up the value a particular name maps to under the given -- substitution; or return Nothing if the name being looked up -- is not in the domain. lookup :: Name a -> Substitution a -> Maybe a instance GHC.Show.Show a => GHC.Show.Show (Disco.Subst.Substitution a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Disco.Subst.Substitution a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Disco.Subst.Substitution a) instance GHC.Base.Functor Disco.Subst.Substitution instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty (Disco.Subst.Substitution a) -- | The Disco.Types module defines the set of types used in the -- disco language type system, along with various utility functions. module Disco.Types -- | Base types are the built-in types which form the basis of the disco -- type system, out of which more complex types can be built. data BaseTy -- | The void type, with no inhabitants. [Void] :: BaseTy -- | The unit type, with one inhabitant. [Unit] :: BaseTy -- | Booleans. [B] :: BaseTy -- | Propositions. [P] :: BaseTy -- | Natural numbers. [N] :: BaseTy -- | Integers. [Z] :: BaseTy -- | Fractionals (i.e. nonnegative rationals). [F] :: BaseTy -- | Rationals. [Q] :: BaseTy -- | Unicode characters. [C] :: BaseTy [Gen] :: BaseTy -- | Set container type. It's a bit odd putting these here since they have -- kind * -> * and all the other base types have kind *; but there's -- nothing fundamentally wrong with it and in particular this allows us -- to reuse all the existing constraint solving machinery for container -- subtyping. [CtrSet] :: BaseTy -- | Bag container type. [CtrBag] :: BaseTy -- | List container type. [CtrList] :: BaseTy -- | Test whether a BaseTy is a container (set, bag, or list). isCtr :: BaseTy -> Bool -- | Var represents type variables, that is, variables which -- stand for some type. data Var [V] :: Ilk -> Name Type -> Var -- | Var represents type variables, that is, variables which -- stand for some type. There are two kinds of type variables: -- --
-- f x (0,z) = 3*x + z > 5 -- f x (y,z) = z == 9 -- ---- -- might look like Defn f [Z, Z*Z] B [clause 1 ..., clause 2 -- ...] data Defn Defn :: Name ATerm -> [Type] -> Type -> NonEmpty Clause -> Defn -- | A clause in a definition consists of a list of patterns (the LHS of -- the =) and a term (the RHS). For example, given the concrete syntax -- f n (x,y) = n*x + y, the corresponding Clause would be -- something like [n, (x,y)] (n*x + y). type Clause = Bind [APattern] ATerm eraseClause :: Clause -> Bind [Pattern] Term -- | Type checking a module yields a value of type ModuleInfo which -- contains mapping from terms to their relavent documenation, a mapping -- from terms to properties, and a mapping from terms to their types. data ModuleInfo ModuleInfo :: ModuleName -> Map ModuleName ModuleInfo -> [QName Term] -> Ctx Term Docs -> Ctx ATerm [AProperty] -> TyCtx -> TyDefCtx -> Ctx ATerm Defn -> [(ATerm, PolyType)] -> ExtSet -> ModuleInfo [_miName] :: ModuleInfo -> ModuleName [_miImports] :: ModuleInfo -> Map ModuleName ModuleInfo [_miNames] :: ModuleInfo -> [QName Term] [_miDocs] :: ModuleInfo -> Ctx Term Docs [_miProps] :: ModuleInfo -> Ctx ATerm [AProperty] [_miTys] :: ModuleInfo -> TyCtx [_miTydefs] :: ModuleInfo -> TyDefCtx [_miTermdefs] :: ModuleInfo -> Ctx ATerm Defn [_miTerms] :: ModuleInfo -> [(ATerm, PolyType)] [_miExts] :: ModuleInfo -> ExtSet miTys :: Lens' ModuleInfo TyCtx miTydefs :: Lens' ModuleInfo TyDefCtx miTerms :: Lens' ModuleInfo [(ATerm, PolyType)] miTermdefs :: Lens' ModuleInfo (Ctx ATerm Defn) miProps :: Lens' ModuleInfo (Ctx ATerm [AProperty]) miNames :: Lens' ModuleInfo [QName Term] miName :: Lens' ModuleInfo ModuleName miImports :: Lens' ModuleInfo (Map ModuleName ModuleInfo) miExts :: Lens' ModuleInfo ExtSet miDocs :: Lens' ModuleInfo (Ctx Term Docs) -- | Get something from a module and its direct imports. withImports :: Monoid a => Getting a ModuleInfo a -> ModuleInfo -> a -- | Get the types of all names bound in a module and its direct imports. allTys :: ModuleInfo -> TyCtx -- | Get all type definitions from a module and its direct imports. allTydefs :: ModuleInfo -> TyDefCtx -- | The empty module info record. emptyModuleInfo :: ModuleInfo -- | A data type indicating where we should look for Disco modules to be -- loaded. data Resolver -- | Load only from the stdlib (standard lib modules) FromStdlib :: Resolver -- | Load only from a specific directory (:load) FromDir :: FilePath -> Resolver -- | Load from current working dir or stdlib (import at REPL) FromCwdOrStdlib :: Resolver -- | Load from specific dir or stdlib (import in file) FromDirOrStdlib :: FilePath -> Resolver -- | Add the possibility of loading imports from the stdlib. For example, -- this is what we want to do after a user loads a specific file using -- `:load` (for which we will NOT look in the stdlib), but then we need -- to recursively load modules which it imports (which may either be in -- the stdlib, or the same directory as the `:load`ed module). withStdlib :: Resolver -> Resolver -- | Given a module resolution mode and a raw module name, relavent -- directories are searched for the file containing the provided module -- name. Returns Nothing if no module with the given name could be found. resolveModule :: Member (Embed IO) r => Resolver -> String -> Sem r (Maybe (FilePath, ModuleProvenance)) instance GHC.Base.Semigroup Disco.Module.ModuleInfo instance GHC.Base.Monoid Disco.Module.ModuleInfo instance Unbound.Generics.LocallyNameless.Subst.Subst Disco.Types.Type Disco.Module.Defn instance Data.Data.Data Disco.Module.Defn instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Module.Defn instance GHC.Generics.Generic Disco.Module.Defn instance GHC.Show.Show Disco.Module.Defn instance GHC.Show.Show Disco.Module.ModuleInfo instance Disco.Pretty.Pretty Disco.Module.Defn -- | Parser to convert concrete Disco syntax into an (untyped, surface -- language) AST. module Disco.Parser data DiscoParseError ReservedVarName :: String -> DiscoParseError InvalidPattern :: OpaqueTerm -> DiscoParseError MissingAscr :: DiscoParseError MultiArgLambda :: DiscoParseError -- | A parser is a megaparsec parser of strings, with an extra layer of -- state to keep track of the current indentation level and language -- extensions, and some custom error messages. type Parser = StateT ParserState (Parsec DiscoParseError String) -- | Run a parser from the initial state. runParser :: Parser a -> FilePath -> String -> Either (ParseErrorBundle String DiscoParseError) a -- | Locally set the enabled extensions within a subparser. withExts :: Set Ext -> Parser a -> Parser a -- | indented p is just like p, except that every token -- must not start in the first column. indented :: Parser a -> Parser a -- | indented p is just like p, except that every token -- after the first must not start in the first column. thenIndented :: Parser a -> Parser a -- | Generically consume whitespace, including comments. sc :: Parser () -- | Parse a lexeme, that is, a parser followed by consuming whitespace. lexeme :: Parser a -> Parser a -- | Parse a given string as a lexeme. symbol :: String -> Parser String -- | Parse a reserved operator. reservedOp :: String -> Parser () -- | Parse a natural number. natural :: Parser Integer -- | Parse a reserved word. reserved :: String -> Parser () -- | The list of all reserved words. reservedWords :: [String] -- | Parse an identifier and turn it into a Name. ident :: Parser (Name Term) parens :: Parser a -> Parser a braces :: Parser a -> Parser a angles :: Parser a -> Parser a brackets :: Parser a -> Parser a semi :: Parser String comma :: Parser String colon :: Parser String dot :: Parser String pipe :: Parser String -- | The symbol that starts an anonymous function (either a backslash or a -- Greek λ). lambda :: Parser String -- | Parse the entire input as a module (with leading whitespace and no -- leftovers). wholeModule :: LoadingMode -> Parser Module -- | Parse an entire module (a list of declarations ended by semicolons). -- The LoadingMode parameter tells us whether to include or -- replace any language extensions enabled at the top level. We include -- them when parsing a module entered at the REPL, and replace them when -- parsing a standalone module. parseModule :: LoadingMode -> Parser Module -- | Parse the name of a language extension (case-insensitive). parseExtName :: Parser Ext -- | Parse a top level item (either documentation or a declaration), which -- must start at the left margin. parseTopLevel :: Parser TopLevel -- | Parse a single top-level declaration (either a type declaration or -- single definition clause). parseDecl :: Parser Decl -- | Parse an import, of the form import modulename. parseImport :: Parser String -- | Parse the name of a module. parseModuleName :: Parser String -- | Parse the entire input as a term (with leading whitespace and no -- leftovers). term :: Parser Term -- | Parse a term, consisting of a parseTerm' optionally followed -- by an ascription. parseTerm :: Parser Term -- | Parse a non-atomic, non-ascribed term. parseTerm' :: Parser Term -- | Parse an expression built out of unary and binary operators. parseExpr :: Parser Term -- | Parse an atomic term. parseAtom :: Parser Term -- | Parse a container, like a literal list, set, bag, or a comprehension -- (not including the square or curly brackets). -- --
-- container-contents
-- ::= nonempty-container | empty
--
-- nonempty-container ::= term container-end
--
-- container-end
-- ::= '|' comprehension
-- | (',' term)* [ ellipsis ]
--
-- comprehension ::= qual [ ',' qual ]*
--
-- qual
-- ::= ident 'in' term
-- | term
--
-- ellipsis ::= [ ',' ] '..' [ ',' ] term
--
parseContainer :: Container -> Parser Term
-- | Parse an ellipsis at the end of a literal list, of the form ..
-- t. Any number > 1 of dots may be used, just for fun.
parseEllipsis :: Parser (Ellipsis Term)
-- | Parse the part of a list comprehension after the | (without square
-- brackets), i.e. a list of qualifiers.
--
-- -- q [,q]* --parseContainerComp :: Container -> Term -> Parser Term -- | Parse a qualifier in a comprehension: either a binder x in t -- or a guard t. parseQual :: Parser Qual -- | Parse a let expression (let x1 = t1, x2 = t2, ... in t). parseLet :: Parser Term parseTypeOp :: Parser Term -- | Parse a case expression. parseCase :: Parser Term -- | Parse one branch of a case expression. parseBranch :: Parser Branch -- | Parse the list of guards in a branch. otherwise can be used -- interchangeably with an empty list of guards. parseGuards :: Parser (Telescope Guard) -- | Parse a single guard (if, if ... is ..., or -- let) parseGuard :: Parser Guard -- | Parse a pattern, by parsing a term and then attempting to convert it -- to a pattern. The Bool parameter says whether to require a type -- ascription. parsePattern :: Bool -> Parser Pattern -- | Parse an atomic pattern, by parsing a term and then attempting to -- convert it to a pattern. parseAtomicPattern :: Parser Pattern -- | Parse a type expression built out of binary operators. parseType :: Parser Type -- | Parse an atomic type. parseAtomicType :: Parser Type parsePolyTy :: Parser PolyType instance GHC.Classes.Ord Disco.Parser.DiscoParseError instance GHC.Classes.Eq Disco.Parser.DiscoParseError instance GHC.Show.Show Disco.Parser.DiscoParseError instance Text.Megaparsec.Error.ShowErrorComponent Disco.Parser.DiscoParseError instance GHC.Show.Show Disco.Parser.OpaqueTerm instance GHC.Classes.Eq Disco.Parser.OpaqueTerm instance GHC.Classes.Ord Disco.Parser.OpaqueTerm -- | Type for collecting all potential Disco errors at the top level, and a -- type for runtime errors. module Disco.Error -- | Top-level error type for Disco. data DiscoError -- | Module not found. [ModuleNotFound] :: String -> DiscoError -- | Cyclic import encountered. [CyclicImport] :: [ModuleName] -> DiscoError -- | Error encountered during typechecking. [TypeCheckErr] :: LocTCError -> DiscoError -- | Error encountered during parsing. [ParseErr] :: ParseErrorBundle String DiscoParseError -> DiscoError -- | Error encountered at runtime. [EvalErr] :: EvalError -> DiscoError -- | Something that shouldn't happen; indicates the presence of a bug. [Panic] :: String -> DiscoError -- | Errors that can be generated at runtime. data EvalError -- | An unbound name was encountered. [UnboundError] :: QName core -> EvalError -- | An unbound name that really shouldn't happen, coming from some kind of -- internal name generation scheme. [UnboundPanic] :: Name core -> EvalError -- | Division by zero. [DivByZero] :: EvalError -- | Overflow, e.g. (2^66)! [Overflow] :: EvalError -- | Non-exhaustive case analysis. [NonExhaustive] :: EvalError -- | Infinite loop detected via black hole. [InfiniteLoop] :: EvalError -- | User-generated crash. [Crash] :: String -> EvalError panic :: Member (Error DiscoError) r => String -> Sem r a outputDiscoErrors :: Member (Output (Message ann)) r => Sem (Error DiscoError ': r) () -> Sem r () instance GHC.Show.Show Disco.Error.DiscoError instance GHC.Show.Show Disco.Error.EvalError instance Disco.Pretty.Pretty Disco.Error.DiscoError -- | Disco runtime values and environments. module Disco.Value -- | Different types of values which can result from the evaluation -- process. data Value -- | A numeric value. [VNum] :: Rational -> Value -- | A built-in function constant. [VConst] :: Op -> Value -- | An injection into a sum type. [VInj] :: Side -> Value -> Value -- | The unit value. [VUnit] :: Value -- | A pair of values. [VPair] :: Value -> Value -> Value -- | A closure, i.e. a function body together with its environment. [VClo] :: Maybe (Int, [Value]) -> Env -> [Name Core] -> Core -> Value -- | A disco type can be a value. For now, there are only a very limited -- number of places this could ever show up (in particular, as an -- argument to enumerate or count). [VType] :: Type -> Value -- | A reference, i.e. a pointer to a memory cell. This is used to -- implement (optional, user-requested) laziness as well as recursion. [VRef] :: Int -> Value -- | A literal function value. VFun is only used when enumerating -- function values in order to decide comparisons at higher-order -- function types. For example, in order to compare two values of type -- (Bool -> Bool) -> Bool for equality, we have to -- enumerate all functions of type Bool -> Bool as -- VFun values. -- -- We assume that all VFun values are strict, that is, -- their arguments should be fully evaluated to RNF before being passed -- to the function. [VFun_] :: ValFun -> Value -- | A proposition. [VProp] :: ValProp -> Value -- | A literal bag, containing a finite list of (perhaps only partially -- evaluated) values, each paired with a count. This is also used to -- represent sets (with the invariant that all counts are equal to 1). [VBag] :: [(Value, Integer)] -> Value -- | A graph, stored using an algebraic repesentation. [VGraph] :: Graph SimpleValue -> Value -- | A map from keys to values. Differs from functions because we can -- actually construct the set of entries, while functions only have this -- property when the key type is finite. [VMap] :: Map SimpleValue Value -> Value [VGen] :: StdGen -> Value -- | Convenient pattern for the empty list. pattern VNil :: Value -- | Convenient pattern for list cons. pattern VCons :: Value -> Value -> Value pattern VFun :: (Value -> Value) -> Value -- | Values which can be used as keys in a map, i.e. those for which a -- Haskell Ord instance can be easily created. These should always be of -- a type for which the QSimple qualifier can be constructed. At the -- moment these are always fully evaluated (containing no indirections) -- and thus don't need memory management. At some point in the future -- constructors for simple graphs and simple maps could be created, if -- the value type is also QSimple. The only reason for actually doing -- this would be constructing graphs of graphs or maps of maps, or the -- like. data SimpleValue [SNum] :: Rational -> SimpleValue [SUnit] :: SimpleValue [SInj] :: Side -> SimpleValue -> SimpleValue [SPair] :: SimpleValue -> SimpleValue -> SimpleValue [SBag] :: [(SimpleValue, Integer)] -> SimpleValue [SType] :: Type -> SimpleValue toSimpleValue :: Value -> SimpleValue fromSimpleValue :: SimpleValue -> Value ratv :: Rational -> Value vrat :: Value -> Rational -- | A convenience function for creating a default VNum value with -- a default (Fractional) flag. intv :: Integer -> Value vint :: Value -> Integer charv :: Char -> Value vchar :: Value -> Char boolv :: Bool -> Value vbool :: Value -> Bool pairv :: (a -> Value) -> (b -> Value) -> (a, b) -> Value vpair :: (Value -> a) -> (Value -> b) -> Value -> (a, b) listv :: (a -> Value) -> [a] -> Value vlist :: (Value -> a) -> Value -> [a] genv :: StdGen -> Value vgen :: Value -> StdGen -- | A ValProp is the normal form of a Disco value of type -- Prop. data ValProp -- | A prop that has already either succeeded or failed. VPDone :: TestResult -> ValProp -- | A pending search. VPSearch :: SearchMotive -> [Type] -> Value -> TestEnv -> ValProp -- | A binary logical operator combining two prop values. VPBin :: LOp -> ValProp -> ValProp -> ValProp -- | The possible outcomes of a proposition. data TestResult TestResult :: Bool -> TestReason -> TestEnv -> TestResult -- | The possible outcomes of a property test, parametrized over the type -- of values. A TestReason explains why a proposition succeeded -- or failed. data TestReason_ a -- | The prop evaluated to a boolean. TestBool :: TestReason_ a -- | The test was a comparison. Records the comparison operator, the values -- being compared, and also their type (which is needed for printing). TestCmp :: BOp -> Type -> a -> a -> TestReason_ a -- | The search didn't find any examples/counterexamples. TestNotFound :: SearchType -> TestReason_ a -- | The search found an example/counterexample. TestFound :: TestResult -> TestReason_ a -- | A binary logical operator was used to combine the given two results. TestBin :: LOp -> TestResult -> TestResult -> TestReason_ a -- | The prop failed at runtime. This is always a failure, no matter which -- quantifiers or negations it's under. TestRuntimeError :: EvalError -> TestReason_ a type TestReason = TestReason_ Value data SearchType -- | All possibilities were checked. Exhaustive :: SearchType -- | A number of small cases were checked exhaustively and then a number of -- additional cases were checked at random. Randomized :: Integer -> Integer -> SearchType -- | The answer (success or failure) we're searching for, and the result -- (success or failure) we return when we find it. The motive (False, -- False) corresponds to a "forall" quantifier (look for a -- counterexample, fail if you find it) and the motive (True, -- True) corresponds to "exists". The other values arise from -- negations. newtype SearchMotive SearchMotive :: (Bool, Bool) -> SearchMotive pattern SMExists :: SearchMotive pattern SMForall :: SearchMotive -- | A collection of variables that might need to be reported for a test, -- along with their types and user-legible names. newtype TestVars TestVars :: [(String, Type, Name Core)] -> TestVars -- | A variable assignment found during a test. newtype TestEnv TestEnv :: [(String, Type, Value)] -> TestEnv emptyTestEnv :: TestEnv mergeTestEnv :: TestEnv -> TestEnv -> TestEnv getTestEnv :: TestVars -> Env -> Either EvalError TestEnv extendPropEnv :: TestEnv -> ValProp -> ValProp extendResultEnv :: TestEnv -> TestResult -> TestResult -- | Whether the property test resulted in success. testIsOk :: TestResult -> Bool -- | Whether the property test resulted in a runtime error. testIsError :: TestResult -> Bool -- | The reason the property test had this result. testReason :: TestResult -> TestReason testEnv :: TestResult -> TestEnv resultIsCertain :: TestReason -> Bool -- | Binary logical operators. data LOp LAnd :: LOp LOr :: LOp LImpl :: LOp interpLOp :: LOp -> Bool -> Bool -> Bool -- | An environment is a mapping from names to values. type Env = Ctx Core Value data Cell Blackhole :: Cell E :: Env -> Core -> Cell V :: Value -> Cell -- | Mem represents a memory, containing Cells data Mem emptyMem :: Mem -- | Allocate a new memory cell containing an unevaluated expression with -- the current environment. Return the index of the allocated cell. allocate :: Members '[State Mem] r => Env -> Core -> Sem r Int allocateValue :: Members '[State Mem] r => Value -> Sem r Int -- | Allocate new memory cells for a group of mutually recursive bindings, -- and return the indices of the allocate cells. allocateRec :: Members '[State Mem] r => Env -> [(QName Core, Core)] -> Sem r [Int] -- | Look up the cell at a given index. lkup :: Members '[State Mem] r => Int -> Sem r (Maybe Cell) memoLookup :: Members '[State Mem] r => Int -> SimpleValue -> Sem r (Maybe Value) -- | Set the cell at a given index. set :: Members '[State Mem] r => Int -> Cell -> Sem r () memoSet :: Members '[State Mem] r => Int -> SimpleValue -> Value -> Sem r () prettyValue' :: Member (Input TyDefCtx) r => Type -> Value -> Sem r (Doc ann) prettyValue :: Members '[Input TyDefCtx, LFresh, Reader PA] r => Type -> Value -> Sem r (Doc ann) instance GHC.Classes.Ord Disco.Value.SimpleValue instance GHC.Classes.Eq Disco.Value.SimpleValue instance GHC.Show.Show Disco.Value.SimpleValue instance GHC.Show.Show Disco.Value.SearchType instance GHC.Show.Show Disco.Value.SearchMotive instance GHC.Base.Monoid Disco.Value.TestVars instance GHC.Base.Semigroup Disco.Value.TestVars instance GHC.Show.Show Disco.Value.TestVars instance GHC.Enum.Bounded Disco.Value.LOp instance GHC.Enum.Enum Disco.Value.LOp instance GHC.Show.Show Disco.Value.LOp instance GHC.Classes.Ord Disco.Value.LOp instance GHC.Classes.Eq Disco.Value.LOp instance GHC.Base.Monoid Disco.Value.TestEnv instance GHC.Base.Semigroup Disco.Value.TestEnv instance GHC.Show.Show Disco.Value.TestEnv instance Data.Traversable.Traversable Disco.Value.TestReason_ instance Data.Foldable.Foldable Disco.Value.TestReason_ instance GHC.Base.Functor Disco.Value.TestReason_ instance GHC.Show.Show a => GHC.Show.Show (Disco.Value.TestReason_ a) instance GHC.Show.Show Disco.Value.TestResult instance GHC.Show.Show Disco.Value.ValProp instance GHC.Show.Show Disco.Value.Value instance GHC.Show.Show Disco.Value.Cell instance GHC.Show.Show Disco.Value.Mem instance GHC.Show.Show Disco.Value.ValFun -- | Enumerate values inhabiting Disco types. module Disco.Enumerate type ValueEnumeration = IEnumeration Value -- | Enumerate all values of type Void (none). enumVoid :: ValueEnumeration -- | Enumerate all values of type Unit (the single value -- unit). enumUnit :: ValueEnumeration -- | Enumerate the values of type Bool as [false, true]. enumBool :: ValueEnumeration -- | Enumerate all values of type Nat (0, 1, 2, ...). enumN :: ValueEnumeration -- | Enumerate all values of type Integer (0, 1, -1, 2, -2, ...). enumZ :: ValueEnumeration -- | Enumerate all values of type Fractional in the Calkin-Wilf -- order (1, 12, 2, 13, 32, 23, 3, ...). enumF :: ValueEnumeration -- | Enumerate all values of type Rational in the Calkin-Wilf -- order, with negatives interleaved (0, 1, -1, 12, -12, 2, -2, -- ...). enumQ :: ValueEnumeration -- | Enumerate all Unicode characters. enumC :: ValueEnumeration -- | Enumerate all *finite* sets over a certain element type, given an -- enumeration of the elements. If we think of each finite set as a -- binary string indicating which elements in the enumeration are -- members, the sets are enumerated in order of the binary strings. enumSet :: ValueEnumeration -> ValueEnumeration -- | Enumerate all *finite* lists over a certain element type, given an -- enumeration of the elements. It is very difficult to describe the -- order in which the lists are generated. enumList :: ValueEnumeration -> ValueEnumeration -- | Enumerate the values of a given type. enumType :: Type -> ValueEnumeration -- | Enumerate a finite product of types. enumTypes :: [Type] -> IEnumeration [Value] -- | Produce an actual list of the values of a type. enumerateType :: Type -> [Value] -- | Produce an actual list of values enumerated from a finite product of -- types. enumerateTypes :: [Type] -> [[Value]] -- | Typecheck the Disco surface language and transform it into a -- type-annotated AST. module Disco.Typecheck containerTy :: Container -> Type -> Type containerToCon :: Container -> Con -- | Infer the type of a telescope, given a way to infer the type of each -- item along with a context of variables it binds; each such context is -- then added to the overall context when inferring subsequent items in -- the telescope. inferTelescope :: (Alpha b, Alpha tyb, Member (Reader TyCtx) r) => (b -> Sem r (tyb, TyCtx)) -> Telescope b -> Sem r (Telescope tyb, TyCtx) suggestionsFrom :: String -> [String] -> [String] -- | Check all the types and extract all relevant info (docs, properties, -- types) from a module, returning a ModuleInfo record on success. -- This function does not handle imports at all; any imports should -- already be checked and passed in as the second argument. checkModule :: Members '[Output (Message ann), Reader TyCtx, Reader TyDefCtx, Error LocTCError, Fresh] r => ModuleName -> Map ModuleName ModuleInfo -> Module -> Sem r ModuleInfo -- | Turn a list of type definitions into a TyDefCtx, checking for -- duplicate names among the definitions and also any type definitions -- already in the context. makeTyDefnCtx :: Members '[Reader TyDefCtx, Error TCError] r => [TypeDefn] -> Sem r TyDefCtx -- | Check the validity of a type definition. checkTyDefn :: Members '[Reader TyDefCtx, Error LocTCError] r => ModuleName -> TypeDefn -> Sem r () -- | Check if a given type is cyclic. A type ty is cyclic if: -- --
-- >>> filterDups [1,3,2,1,1,4,2] -- [1,2] --filterDups :: Ord a => [a] -> [a] -- | Given a list of type declarations from a module, first check that -- there are no duplicate type declarations, and that the types are -- well-formed; then create a type context containing the given -- declarations. makeTyCtx :: Members '[Reader TyDefCtx, Error TCError] r => ModuleName -> [TypeDecl] -> Sem r TyCtx -- | Check that all the types in a context are valid. checkCtx :: Members '[Reader TyDefCtx, Error TCError] r => TyCtx -> Sem r () -- | Type check a top-level definition in the given module. checkDefn :: Members '[Reader TyCtx, Reader TyDefCtx, Error LocTCError, Fresh, Output (Message ann)] r => ModuleName -> TermDefn -> Sem r Defn -- | Given a context mapping names to documentation, extract the properties -- attached to each name and typecheck them. checkProperties :: Members '[Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh, Output (Message ann)] r => Ctx Term Docs -> Sem r (Ctx ATerm [AProperty]) -- | Check the types of the terms embedded in a property. checkProperty :: Members '[Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh, Output (Message ann)] r => Property -> Sem r AProperty -- | Check that a sigma type is a valid type. See checkTypeValid. checkPolyTyValid :: Members '[Reader TyDefCtx, Error TCError] r => PolyType -> Sem r () -- | Disco doesn't need kinds per se, since all types must be fully -- applied. But we do need to check that every type is applied to the -- correct number of arguments. checkTypeValid :: Members '[Reader TyDefCtx, Error TCError] r => Type -> Sem r () conArity :: Members '[Reader TyDefCtx, Error TCError] r => Con -> Sem r Int -- | Typechecking can be in one of two modes: inference mode means we are -- trying to synthesize a valid type for a term; checking mode means we -- are trying to show that a term has a given type. data Mode Infer :: Mode Check :: Type -> Mode -- | Check that a term has the given type. Either throws an error, or -- returns the term annotated with types for all subterms. -- -- This function is provided for convenience; it simply calls -- typecheck with an appropriate Mode. check :: Members '[Reader TyCtx, Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Term -> Type -> Sem r ATerm -- | Check that a term has the given polymorphic type. checkPolyTy :: Members '[Reader TyCtx, Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Term -> PolyType -> Sem r ATerm -- | Infer the type of a term. If it succeeds, it returns the term with all -- subterms annotated. -- -- This function is provided for convenience; it simply calls -- typecheck with an appropriate Mode. infer :: Members '[Reader TyCtx, Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Term -> Sem r ATerm -- | Top-level type inference algorithm, returning only the first possible -- result. inferTop1 :: Members '[Output (Message ann), Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh] r => Term -> Sem r (ATerm, PolyType) -- | Top-level type inference algorithm: infer up to the requested max -- number of possible (polymorphic) types for a term by running type -- inference, solving the resulting constraints, and quantifying over any -- remaining type variables. inferTop :: Members '[Output (Message ann), Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh] r => Int -> Term -> Sem r (NonEmpty (ATerm, PolyType)) -- | Top-level type checking algorithm: check that a term has a given -- polymorphic type by running type checking and solving the resulting -- constraints. checkTop :: Members '[Output (Message ann), Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh] r => Term -> PolyType -> Sem r ATerm -- | The main workhorse of the typechecker. Instead of having two -- functions, one for inference and one for checking, typecheck -- takes a Mode. This cuts down on code duplication in many cases, -- and allows all the checking and inference code related to a given AST -- node to be placed together. typecheck :: Members '[Reader TyCtx, Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Mode -> Term -> Sem r ATerm -- | Check that a pattern has the given type, and return a context of -- pattern variables bound in the pattern along with their types. checkPattern :: Members '[Reader TyCtx, Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Pattern -> Type -> Sem r (TyCtx, APattern) -- | Constraints needed on a function type for it to be the type of the -- absolute value function. cAbs :: Members '[Writer Constraint, Fresh] r => Type -> Type -> Sem r () -- | Constraints needed on a function type for it to be the type of the -- container size operation. cSize :: Members '[Writer Constraint, Fresh] r => Type -> Type -> Sem r () -- | Given an input type ty, return a type which represents the -- output type of the absolute value function, and generate appropriate -- constraints. cPos :: Members '[Writer Constraint, Fresh] r => Type -> Sem r Type -- | Given an input type ty, return a type which represents the -- output type of the floor or ceiling functions, and generate -- appropriate constraints. cInt :: Members '[Writer Constraint, Fresh] r => Type -> Sem r Type -- | Given input types to the exponentiation operator, return a type which -- represents the output type, and generate appropriate constraints. cExp :: Members '[Writer Constraint, Fresh] r => Type -> Type -> Sem r Type -- | Get the argument (element) type of a (known) container type. Returns a -- fresh variable with a suitable constraint if the given type is not -- literally a container type. getEltTy :: Members '[Writer Constraint, Fresh] r => Container -> Type -> Sem r Type -- | Ensure that a type's outermost constructor matches the provided -- constructor, returning the types within the matched constructor or -- throwing a type error. If the type provided is a type variable, -- appropriate constraints are generated to guarantee the type variable's -- outermost constructor matches the provided constructor, and a list of -- fresh type variables is returned whose count matches the arity of the -- provided constructor. ensureConstr :: forall r. Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Type -> Either Term Pattern -> Sem r [Type] -- | A variant of ensureConstr that expects to get exactly one argument -- type out, and throws an error if we get any other number. ensureConstr1 :: Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Type -> Either Term Pattern -> Sem r Type -- | A variant of ensureConstr that expects to get exactly two argument -- types out, and throws an error if we get any other number. ensureConstr2 :: Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Type -> Either Term Pattern -> Sem r (Type, Type) -- | A variant of ensureConstr that works on Modes instead of -- Types. Behaves similarly to ensureConstr if the -- Mode is Check; otherwise it generates an appropriate -- number of copies of Infer. ensureConstrMode :: Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Mode -> Either Term Pattern -> Sem r [Mode] -- | A variant of ensureConstrMode that expects to get a single -- Mode and throws an error if it encounters any other number. ensureConstrMode1 :: Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Mode -> Either Term Pattern -> Sem r Mode -- | A variant of ensureConstrMode that expects to get two -- Modes and throws an error if it encounters any other number. ensureConstrMode2 :: Members '[Reader TyDefCtx, Writer Constraint, Error TCError, Fresh] r => Con -> Mode -> Either Term Pattern -> Sem r (Mode, Mode) -- | Ensure that two types are equal: 1. Do nothing if they are literally -- equal 2. Generate an equality constraint otherwise ensureEq :: Member (Writer Constraint) r => Type -> Type -> Sem r () isSubPolyType :: Members '[Input TyDefCtx, Output (Message ann), Fresh] r => PolyType -> PolyType -> Sem r Bool thin :: Members '[Input TyDefCtx, Output (Message ann), Fresh] r => NonEmpty PolyType -> Sem r (NonEmpty PolyType) thin' :: Members '[Input TyDefCtx, Output (Message ann), Fresh] r => [PolyType] -> Sem r [PolyType] instance GHC.Show.Show Disco.Typecheck.Mode -- | Utilities for converting Disco types into Constructors that the -- exhaustiveness checker understands, and utilities for working with -- TypedVars and their names. module Disco.Exhaustiveness.TypeInfo newtype TypedVar TypedVar :: (Name ATerm, Type) -> TypedVar getType :: TypedVar -> Type data DataCon DataCon :: Ident -> [Type] -> DataCon [dcIdent] :: DataCon -> Ident [dcTypes] :: DataCon -> [Type] data Ident [KUnit] :: Ident [KBool] :: Bool -> Ident [KNat] :: Integer -> Ident [KInt] :: Integer -> Ident [KPair] :: Ident [KCons] :: Ident [KNil] :: Ident [KChar] :: Char -> Ident [KLeft] :: Ident [KRight] :: Ident [KUnknown] :: Ident -- | Finite constructors are used in the LYG checker Infinite -- constructors are used when reporting examples of uncovered patterns, -- we only pick out a few of them data Constructors [Finite] :: [DataCon] -> Constructors [Infinite] :: [DataCon] -> Constructors unknown :: DataCon unit :: DataCon bool :: Bool -> DataCon natural :: Integer -> DataCon integer :: Integer -> DataCon char :: Char -> DataCon cons :: Type -> Type -> DataCon nil :: DataCon pair :: Type -> Type -> DataCon left :: Type -> DataCon right :: Type -> DataCon tyDataCons :: Type -> TyDefCtx -> Constructors resolveAlias :: Type -> TyDefCtx -> Type -- | Assuming type aliases have been resolved, this function converts Disco -- types into lists of DataCons that are compatible with the LYG checker. -- -- A list of constructors is Infinite if the only way to fully -- match against the type is with a wildcard or variable pattern. -- Otherwise, it is Finite. -- -- The LYG checker only reads the list of constructors if a type is -- Finite. From the point of view of the checker, Infinite -- is a synonym for opaque, and the constructors are discarded. The -- dataconstructors in an Infinite list are only used when -- generating the 3 positive examples of what you haven't matched -- against. This will probably need to change a bit when bringing -- exhaustiveness checking to the new arithmetic patterns. -- -- Notice the last case of this function, which a wildcard handling the -- types: (_ Ty.:->: _) (Ty.TySet _) (Ty.TyBag _) (Ty.TyVar _) -- (Ty.TySkolem _) (Ty.TyProp) (Ty.TyMap _ _) (Ty.TyGraph _) -- -- I believe all of these are impossible to pattern match against with -- anything other than a wildcard (or variable pattern) in Disco, so they -- should always be fully covered. But if they are in a pair, for -- example, Set(Int)*Int, we still need to generate 3 examples of the -- pair if that Int part isn't covered. So how do we fill the concrete -- part of Set(Int), (or a generic type "a", or a function, etc.)? I'm -- calling that unknown, and printing an underscore. (Also, I'm -- using Infinite for reasons metioned above). tyDataConsHelper :: Type -> Constructors newName :: Member Fresh r => Sem r (Name ATerm) newVar :: Member Fresh r => Type -> Sem r TypedVar newNames :: Member Fresh r => Int -> Sem r [Name ATerm] newVars :: Member Fresh r => [Type] -> Sem r [TypedVar] instance GHC.Classes.Ord Disco.Exhaustiveness.TypeInfo.TypedVar instance GHC.Show.Show Disco.Exhaustiveness.TypeInfo.TypedVar instance GHC.Classes.Ord Disco.Exhaustiveness.TypeInfo.Ident instance GHC.Classes.Eq Disco.Exhaustiveness.TypeInfo.Ident instance GHC.Show.Show Disco.Exhaustiveness.TypeInfo.Ident instance GHC.Show.Show Disco.Exhaustiveness.TypeInfo.DataCon instance GHC.Classes.Ord Disco.Exhaustiveness.TypeInfo.DataCon instance GHC.Classes.Eq Disco.Exhaustiveness.TypeInfo.DataCon instance GHC.Classes.Eq Disco.Exhaustiveness.TypeInfo.TypedVar -- | The heart of the Lower Your Guards algorithm. Functions for converting -- constraints detailing pattern matches into a normalized description of -- everything that is left uncovered. module Disco.Exhaustiveness.Constraint data Constraint [CMatch] :: DataCon -> [TypedVar] -> Constraint [CNot] :: DataCon -> Constraint [CWasOriginally] :: TypedVar -> Constraint posMatch :: [Constraint] -> Maybe (DataCon, [TypedVar]) negMatches :: [Constraint] -> [DataCon] type ConstraintFor = (TypedVar, Constraint) lookupVar :: TypedVar -> [ConstraintFor] -> TypedVar alistLookup :: Eq a => a -> [(a, b)] -> [b] onVar :: TypedVar -> [ConstraintFor] -> [Constraint] type NormRefType = [ConstraintFor] addConstraints :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> [ConstraintFor] -> MaybeT (Sem r) NormRefType addConstraint :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> ConstraintFor -> MaybeT (Sem r) NormRefType addConstraintHelper :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> ConstraintFor -> MaybeT (Sem r) NormRefType breakIf :: Alternative f => Bool -> f () -- | Returns a predicate that returns true if another constraint conflicts -- with the one given. This alone is not sufficient to test if a -- constraint can be added, but it filters out the easy negatives early -- on conflictsWith :: Constraint -> Constraint -> Bool -- | Search for a MatchDataCon that is matching on k specifically (there -- should be at most one, see I4 in section 3.4) and if it exists, return -- the variable ids of its arguments getConstructorArgs :: DataCon -> [Constraint] -> Maybe [TypedVar] -- | substituting y *for* x ie replace the second with the first, replace x -- with y substituteVarIDs :: TypedVar -> TypedVar -> [ConstraintFor] -> [ConstraintFor] -- | Deals with I2 from section 3.4 if a variable in the context has a -- resolvable type, there must be at least one constructor which can be -- instantiated without contradiction of the refinement type This -- function tests if this is true inhabited :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> TypedVar -> Sem r Bool -- | Attempts to "instantiate" a match of the dataconstructor k on x If we -- can add the MatchDataCon constraint to the normalized refinement type -- without contradiction (a Nothing value), then x is inhabited by k and -- we return true instantiate :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> TypedVar -> DataCon -> Sem r Bool instance GHC.Classes.Ord Disco.Exhaustiveness.Constraint.Constraint instance GHC.Classes.Eq Disco.Exhaustiveness.Constraint.Constraint instance GHC.Show.Show Disco.Exhaustiveness.Constraint.Constraint -- | Entry point into the exhaustiveness checker. Converts information into -- a format the checker understands, then pretty prints the results of -- running it. module Disco.Exhaustiveness -- | This exhaustiveness checking algorithm is based on the paper "Lower -- Your Guards: A Compositional Pattern-Match Coverage Checker": -- https://www.microsoft.com/en-us/research/uploads/prod/2020/03/lyg.pdf -- -- Some simplifications were made to adapt the algorithm to suit Disco. -- The most notable change is that here we always generate (at most) 3 -- concrete examples of uncovered patterns, instead of finding the most -- general complete description of every uncovered input. checkClauses :: Members '[Fresh, Reader TyDefCtx, Output (Message ann), Embed IO] r => Name ATerm -> [Type] -> NonEmpty [APattern] -> Sem r () prettyPrintExample :: ExamplePat -> Sem r (Doc ann) prettyPrintPattern :: Members '[Reader PA, LFresh] r => Pattern -> Sem r (Doc ann) exampleToDiscoPattern :: ExamplePat -> Pattern resugarPair :: ExamplePat -> [ExamplePat] resugarList :: ExamplePat -> [ExamplePat] resugarString :: ExamplePat -> String assumeExampleChar :: ExamplePat -> Char desugarClause :: Members '[Fresh, Embed IO] r => [TypedVar] -> Int -> [APattern] -> Sem r Gdt desugarTuplePats :: [APattern] -> APattern -- | Convert a Disco APattern into a list of Guards which cover that -- pattern -- -- These patterns are currently not handled: , APNeg --still need to -- handle rational case , APFrac --required for rationals? algebraic -- (probably will be eventually replaced anyway): , APAdd , APMul , APSub -- These (or some updated version of them) may be handled eventually, -- once updated arithmetic patterns are merged. -- -- We treat unhandled patterns as if they are exhaustively matched -- against (aka, they are seen as wildcards by the checker). This -- necessarily results in some false negatives, but no false positives. desugarMatch :: Members '[Fresh, Embed IO] r => TypedVar -> APattern -> Sem r [Guard] data Gdt [Grhs] :: Int -> Gdt [Branch] :: Gdt -> Gdt -> Gdt [Guarded] :: Guard -> Gdt -> Gdt type Guard = (TypedVar, GuardConstraint) data GuardConstraint [GMatch] :: DataCon -> [TypedVar] -> GuardConstraint [GWasOriginally] :: TypedVar -> GuardConstraint newtype Literal Literal :: (TypedVar, LitCond) -> Literal data LitCond [LitMatch] :: DataCon -> [TypedVar] -> LitCond [LitNot] :: DataCon -> LitCond [LitWasOriginally] :: TypedVar -> LitCond data Ant [AGrhs] :: [NormRefType] -> Int -> Ant [ABranch] :: Ant -> Ant -> Ant ua :: Members '[Fresh, Reader TyDefCtx] r => [NormRefType] -> Gdt -> Sem r ([NormRefType], Ant) addLitMulti :: Members '[Fresh, Reader TyDefCtx] r => [NormRefType] -> Literal -> Sem r [NormRefType] addLiteral :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> Literal -> MaybeT (Sem r) NormRefType data InhabPat [IPIs] :: DataCon -> [InhabPat] -> InhabPat [IPNot] :: [DataCon] -> InhabPat mkIPMatch :: DataCon -> [InhabPat] -> InhabPat findInhabitants :: Members '[Fresh, Reader TyDefCtx] r => [NormRefType] -> [TypedVar] -> Sem r (Possibilities [InhabPat]) findAllForNref :: Members '[Fresh, Reader TyDefCtx] r => NormRefType -> [TypedVar] -> Sem r (Possibilities [InhabPat]) findVarInhabitants :: Members '[Fresh, Reader TyDefCtx] r => TypedVar -> NormRefType -> Sem r (Possibilities InhabPat) findRedundant :: Members '[Fresh, Reader TyDefCtx] r => Ant -> [TypedVar] -> Sem r [Int] data ExamplePat [ExamplePat] :: DataCon -> [ExamplePat] -> ExamplePat -- | Less general version of the above inhabitant finding function returns -- a maximum of 3 possible args lists that haven't been matched against, -- as to not overwhelm new users of the language. This is essentially a -- DFS, and it has a bad habit of trying to build infinite lists whenever -- it can, so we give it a max depth of 32 If we reach 32 levels of -- nested dataconstructors in this language, it is pretty safe to assume -- we were chasing after an infinite structure findPosExamples :: Members '[Fresh, Reader TyDefCtx] r => [NormRefType] -> [TypedVar] -> Sem r [[ExamplePat]] findAllPosForNref :: Members '[Fresh, Reader TyDefCtx] r => Int -> NormRefType -> [TypedVar] -> Sem r (Possibilities [ExamplePat]) findVarPosExamples :: Members '[Fresh, Reader TyDefCtx] r => Int -> TypedVar -> NormRefType -> Sem r (Possibilities ExamplePat) getPosFrom :: Type -> TyDefCtx -> [DataCon] -> [DataCon] mkExampleMatch :: DataCon -> [ExamplePat] -> ExamplePat instance GHC.Classes.Eq Disco.Exhaustiveness.GuardConstraint instance GHC.Show.Show Disco.Exhaustiveness.GuardConstraint instance GHC.Classes.Eq Disco.Exhaustiveness.Gdt instance GHC.Show.Show Disco.Exhaustiveness.Gdt instance GHC.Classes.Ord Disco.Exhaustiveness.LitCond instance GHC.Classes.Eq Disco.Exhaustiveness.LitCond instance GHC.Show.Show Disco.Exhaustiveness.LitCond instance GHC.Show.Show Disco.Exhaustiveness.Ant instance GHC.Classes.Ord Disco.Exhaustiveness.InhabPat instance GHC.Classes.Eq Disco.Exhaustiveness.InhabPat instance GHC.Show.Show Disco.Exhaustiveness.InhabPat instance GHC.Show.Show Disco.Exhaustiveness.ExamplePat -- | Desugaring the typechecked surface language to a (still typed) simpler -- language. module Disco.Desugar -- | Run a desugaring computation. runDesugar :: Sem '[Fresh] a -> a -- | Desugar a definition (consisting of a collection of pattern clauses -- with bodies) into a core language term. desugarDefn :: Member Fresh r => Defn -> Sem r DTerm -- | Desugar a typechecked term. desugarTerm :: Member Fresh r => ATerm -> Sem r DTerm -- | Desugar a property by wrapping its corresponding term in a test frame -- to catch its exceptions & convert booleans to props. desugarProperty :: Member Fresh r => AProperty -> Sem r DTerm -- | Desugar a branch of a case expression. desugarBranch :: Member Fresh r => ABranch -> Sem r DBranch -- | Desugar the list of guards in one branch of a case expression. Pattern -- guards essentially remain as they are; boolean guards get turned into -- pattern guards which match against true. desugarGuards :: Member Fresh r => Telescope AGuard -> Sem r (Telescope DGuard) -- | Compiling the typechecked, desugared AST to the untyped core language. module Disco.Compile -- | Utility function to desugar and compile a thing, given a desugaring -- function for it. compileThing :: (a -> Sem '[Fresh] DTerm) -> a -> Core -- | Compile a typechecked term (ATerm) directly to a Core -- term, by desugaring and then compiling. compileTerm :: ATerm -> Core -- | Compile a typechecked property (AProperty) directly to a -- Core term, by desugaring and then compilling. compileProperty :: AProperty -> Core -- | Compile a context of typechecked definitions (Defn) to a -- sequence of compiled Core bindings, such that the body of each -- binding depends only on previous ones in the list. First topologically -- sorts the definitions into mutually recursive groups, then compiles -- recursive definitions specially in terms of delay and -- force. compileDefns :: Ctx ATerm Defn -> [(QName Core, Core)] -- | Compile a group of mutually recursive definitions, using -- delay to compile recursion via references to memory cells. compileDefnGroup :: Member Fresh r => [(QName ATerm, Defn)] -> Sem r [(QName Core, Core)] -- | Compile a typechecked, desugared DTerm to an untyped -- Core term. compileDTerm :: Member Fresh r => DTerm -> Sem r Core -- | Compile a natural number. A separate function is needed in case the -- number is of a finite type, in which case we must mod it by its type. -- compileNat :: Member Fresh r => Type -> Integer -> Sem r Core -- compileNat (TyFin n) x = return $ CNum Fraction ((x mod n) % 1) -- compileNat _ x = return $ CNum Fraction (x % 1) -- -- Compile a primitive. Typically primitives turn into a corresponding -- function constant in the core language, but sometimes the particular -- constant it turns into may depend on the type. compilePrim :: Member Fresh r => Type -> Prim -> Sem r Core compilePrimErr :: Prim -> Type -> a desugaredPrimErr :: Prim -> Type -> a -- | Compile a case expression of type τ to a core language expression of -- type (Unit → τ), in order to delay evaluation until explicitly -- applying it to the unit value. compileCase :: Member Fresh r => [DBranch] -> Sem r Core -- | Compile a branch of a case expression of type τ to a core language -- expression of type (Unit → τ) → τ. The idea is that it takes a failure -- continuation representing the subsequent branches in the case -- expression. If the branch succeeds, it just returns the associated -- expression of type τ; if it fails, it calls the continuation to -- proceed with the case analysis. compileBranch :: Member Fresh r => DBranch -> Sem r Core -- | compileGuards takes a list of guards, the name of the failure -- continuation of type (Unit → τ), and a Core term of type τ to return -- in the case of success, and compiles to an expression of type τ which -- evaluates the guards in sequence, ultimately returning the given -- expression if all guards succeed, or calling the failure continuation -- at any point if a guard fails. compileGuards :: Member Fresh r => [DGuard] -> Name Core -> Core -> Sem r Core -- | compileMatch takes a pattern, the compiled scrutinee, the name -- of the failure continuation, and a Core term representing the -- compilation of any guards which come after this one, and returns a -- Core expression of type τ that performs the match and either calls the -- failure continuation in the case of failure, or the rest of the guards -- in the case of success. compileMatch :: Member Fresh r => DPattern -> Core -> Name Core -> Core -> Sem r Core -- | Compile a unary operator. compileUOp :: Type -> UOp -> Core -- | Compile a binary operator. This function needs to know the types of -- the arguments and result since some operators are overloaded and -- compile to different code depending on their type. -- --
-- arg1 ty -> arg2 ty -> result ty -> op -> result --compileBOp :: Type -> Type -> Type -> BOp -> Core -- | Properties of disco functions. module Disco.Property -- | Select samples from an enumeration according to a search type. Also -- returns a SearchType describing the results, which may be -- Exhaustive if the enumeration is no larger than the number of -- samples requested. generateSamples :: Member Random r => SearchType -> IEnumeration a -> Sem r ([a], SearchType) -- | Toggles which outcome (finding or not finding the thing being searched -- for) qualifies as success, without changing the thing being searched -- for. invertMotive :: SearchMotive -> SearchMotive -- | Flips the success or failure status of a PropResult, leaving -- the explanation unchanged. invertPropResult :: TestResult -> TestResult prettyTestResult :: Members '[Input TyDefCtx, LFresh, Reader PA] r => AProperty -> TestResult -> Sem r (Doc ann) -- | CESK machine interpreter for Disco. module Disco.Interpret.CESK -- | The CESK machine has two basic kinds of states. data CESK -- | Run a CESK machine to completion. runCESK :: Members '[Fresh, Random, State Mem] r => CESK -> Sem r (Either EvalError Value) -- | Advance the CESK machine by one step. step :: Members '[Fresh, Random, State Mem] r => CESK -> Sem r CESK eval :: Members '[Random, Error EvalError, Input Env, State Mem] r => Core -> Sem r Value evalApp :: Members '[Random, Error EvalError, State Mem] r => Value -> [Value] -> Sem r Value runTest :: Members '[Random, Error EvalError, Input Env, State Mem] r => Int -> AProperty -> Sem r TestResult instance GHC.Show.Show Disco.Interpret.CESK.Frame instance GHC.Show.Show Disco.Interpret.CESK.CESK -- | Top-level evaluation utilities. module Disco.Eval -- | Effects needed for evaluation. type EvalEffects = [Error EvalError, Random, LFresh, Output (Message ()), State Mem] -- | All effects needed for the top level + evaluation. type DiscoEffects = AppendEffects EvalEffects TopEffects data DiscoConfig initDiscoConfig :: DiscoConfig debugMode :: Iso' DiscoConfig Bool -- | A record of information about the current top-level environment. data TopInfo replModInfo :: Lens' TopInfo ModuleInfo topEnv :: Lens' TopInfo Env topModMap :: Lens' TopInfo (Map ModuleName ModuleInfo) lastFile :: Lens' TopInfo (Maybe FilePath) discoConfig :: Lens' TopInfo DiscoConfig -- | Run a top-level computation. runDisco :: DiscoConfig -> (forall r. Members DiscoEffects r => Sem r ()) -> IO () -- | Run a typechecking computation, providing it with local contexts -- (initialized to the provided arguments) for variable types and type -- definitions. runTCM :: Member (Error DiscoError) r => TyCtx -> TyDefCtx -> Sem (Reader TyCtx ': (Reader TyDefCtx ': (Fresh ': (Error LocTCError ': r)))) a -> Sem r a -- | Run a computation that needs an input environment, grabbing the -- current top-level environment from the TopInfo records. inputTopEnv :: Member (Input TopInfo) r => Sem (Input Env ': r) a -> Sem r a -- | Parse a module from a file, re-throwing a parse error if it fails. parseDiscoModule :: Members '[Error DiscoError, Embed IO] r => FilePath -> Sem r Module -- | Run a typechecking computation in the context of the top-level REPL -- module, re-throwing a wrapped error if it fails. typecheckTop :: Members '[Input TopInfo, Error DiscoError] r => Sem (Reader TyCtx ': (Reader TyDefCtx ': (Fresh ': (Error TCError ': r)))) a -> Sem r a -- | Recursively loads a given module by first recursively loading and -- typechecking its imported modules, adding the obtained -- ModuleInfo records to a map from module names to info records, -- and then typechecking the parent module in an environment with access -- to this map. This is really just a depth-first search. -- -- The Resolver argument specifies where to look for imported -- modules. loadDiscoModule :: Members '[State TopInfo, Output (Message ann), Random, State Mem, Error DiscoError, Embed IO] r => Bool -> Resolver -> FilePath -> Sem r ModuleInfo -- | Like loadDiscoModule, but start with an already parsed -- Module instead of loading a module from disk by name. Also, -- check it in a context that includes the current top-level context -- (unlike a module loaded from disk). Used for e.g. blocks/modules -- entered at the REPL prompt. loadParsedDiscoModule :: Members '[State TopInfo, Output (Message ann), Random, State Mem, Error DiscoError, Embed IO] r => Bool -> Resolver -> ModuleName -> Module -> Sem r ModuleInfo -- | Try loading the contents of a file from the filesystem, emitting an -- error if it's not found. loadFile :: Members '[Output (Message ann), Embed IO] r => FilePath -> Sem r (Maybe String) -- | Add things from the given module to the set of currently loaded -- things. addToREPLModule :: Members '[Error DiscoError, State TopInfo, Random, State Mem, Output (Message ann)] r => ModuleInfo -> Sem r () -- | Set the given ModuleInfo record as the currently loaded module. -- This also includes updating the top-level state with new term -- definitions, documentation, types, and type definitions. Replaces any -- previously loaded module. setREPLModule :: Members '[State TopInfo, Random, Error EvalError, State Mem, Output (Message ann)] r => ModuleInfo -> Sem r () -- | Populate various pieces of the top-level info record (docs, type -- context, type and term definitions) from the ModuleInfo record -- corresponding to the currently loaded module, and load all the -- definitions into the current top-level environment. loadDefsFrom :: Members '[State TopInfo, Random, Error EvalError, State Mem] r => ModuleInfo -> Sem r () loadDef :: Members '[State TopInfo, Random, Error EvalError, State Mem] r => QName Core -> Core -> Sem r () -- | Defining and dispatching all commands/functionality available at the -- REPL prompt. module Disco.Interactive.Commands -- | Given a list of REPL commands and something typed at the REPL, pick -- the first command with a matching type-level tag and run its -- associated action. dispatch :: Members DiscoEffects r => REPLCommands -> SomeREPLExpr -> Sem r () -- | The list of all commands that can be used at the REPL. Resolution of -- REPL commands searches this list in order, which means -- ambiguous command prefixes (e.g. :t for :type) are resolved to the -- first matching command. discoCommands :: REPLCommands handleLoad :: Members (Error DiscoError ': (State TopInfo ': (Output (Message ()) ': (Embed IO ': EvalEffects)))) r => FilePath -> Sem r Bool -- | Try loading the contents of a file from the filesystem, emitting an -- error if it's not found. loadFile :: Members '[Output (Message ann), Embed IO] r => FilePath -> Sem r (Maybe String) -- | Given a list of available REPL commands and the currently enabled -- extensions, parse a string entered at the REPL prompt, returning -- either a parse error message or a parsed REPL expression. parseLine :: REPLCommands -> ExtSet -> String -> Either String SomeREPLExpr instance GHC.Show.Show Disco.Interactive.Commands.REPLCommandCategory instance GHC.Classes.Eq Disco.Interactive.Commands.REPLCommandCategory instance GHC.Show.Show Disco.Interactive.Commands.REPLCommandType instance GHC.Classes.Eq Disco.Interactive.Commands.REPLCommandType instance GHC.Classes.Eq Disco.Interactive.Commands.CmdTag instance GHC.Show.Show Disco.Interactive.Commands.CmdTag instance GHC.Show.Show Disco.Interactive.Commands.DocInput instance GHC.Show.Show Disco.Interactive.Commands.Level instance GHC.Classes.Ord Disco.Interactive.Commands.Level instance GHC.Classes.Eq Disco.Interactive.Commands.Level instance GHC.Show.Show (Disco.Interactive.Commands.REPLExpr c) -- | Definition of the command-line REPL interface for Disco. module Disco.Interactive.CmdLine -- | Command-line options for disco. data DiscoOpts DiscoOpts :: Bool -> Maybe String -> Maybe String -> Maybe String -> Bool -> DiscoOpts -- | Should we just print the version? [onlyVersion] :: DiscoOpts -> Bool -- | A single expression to evaluate [evaluate] :: DiscoOpts -> Maybe String -- | Execute the commands in a given file [cmdFile] :: DiscoOpts -> Maybe String -- | Check a file and then exit [checkFile] :: DiscoOpts -> Maybe String [debugFlag] :: DiscoOpts -> Bool discoOpts :: Parser DiscoOpts discoInfo :: ParserInfo DiscoOpts discoMain :: IO ()