-- 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.1.4 -- | 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 next :: forall r_ajvU. Member Counter r_ajvU => Sem r_ajvU 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 -- | 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_alvM. Member LFresh r_alvM => Sem r_alvM (Set AnyName) avoid :: forall r_alvJ a_alr7. Member LFresh r_alvJ => [AnyName] -> Sem r_alvJ a_alr7 -> Sem r_alvJ a_alr7 lfresh :: forall r_alvH a_Xlr5. (Member LFresh r_alvH, Typeable a_Xlr5) => Name a_Xlr5 -> Sem r_alvH (Name a_Xlr5) -- | 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') -- | Utility functions for random effect. module Disco.Effects.Random -- | Run a QuickCheck generator using a Random effect. runGen :: Member Random r => Gen 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_aon0 r_aoto. Member (Store v_aon0) r_aoto => IntSet -> Sem r_aoto () assocsStore :: forall v_aomY r_aotn. Member (Store v_aomY) r_aotn => Sem r_aotn [(Int, v_aomY)] mapStore :: forall v_aomW r_aotl. Member (Store v_aomW) r_aotl => (v_aomW -> v_aomW) -> Sem r_aotl () insertStore :: forall v_aomU r_aoti. Member (Store v_aomU) r_aoti => Int -> v_aomU -> Sem r_aoti () lookupStore :: forall v_aomS r_aotg. Member (Store v_aomS) r_aotg => Int -> Sem r_aotg (Maybe v_aomS) new :: forall v_aomQ r_aote. Member (Store v_aomQ) r_aote => v_aomQ -> Sem r_aote Int clearStore :: forall v_aomO r_aotd. Member (Store v_aomO) r_aotd => Sem r_aotd () -- | Dispatch a store effect. runStore :: forall v r a. Sem (Store v : r) a -> Sem r 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 -- | Minimum (min) Min :: BOp -- | Maximum (max) Max :: 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 -- | Equality assertion (=!=) ShouldEq :: 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 -- | 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 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 instance GHC.Classes.Ord Disco.Pretty.Prec.PA -- | Adapter DSL on top of Text.PrettyPrint for Applicative -- pretty-printing. module Disco.Pretty.DSL vcat :: Applicative f => [f Doc] -> f Doc hcat :: Applicative f => [f Doc] -> f Doc hsep :: Applicative f => [f Doc] -> f Doc parens :: Functor f => f Doc -> f Doc brackets :: Functor f => f Doc -> f Doc braces :: Functor f => f Doc -> f Doc bag :: Applicative f => f Doc -> f Doc quotes :: Functor f => f Doc -> f Doc doubleQuotes :: Functor f => f Doc -> f Doc text :: Applicative m => String -> m Doc integer :: Applicative m => Integer -> m Doc nest :: Functor f => Int -> f Doc -> f Doc hang :: Applicative f => f Doc -> Int -> f Doc -> f Doc empty :: Applicative m => m Doc (<+>) :: Applicative f => f Doc -> f Doc -> f Doc (<>) :: Applicative f => f Doc -> f Doc -> f Doc ($+$) :: Applicative f => f Doc -> f Doc -> f Doc punctuate :: Applicative f => f Doc -> [f Doc] -> f [f Doc] intercalate :: Monad f => f Doc -> [f Doc] -> f Doc bulletList :: Applicative f => f Doc -> [f Doc] -> f Doc renderDoc :: Sem (Reader PA : r) Doc -> Sem r String renderDoc' :: Doc -> String instance Data.String.IsString (Polysemy.Internal.Sem r Text.PrettyPrint.HughesPJ.Doc) -- | Various pretty-printing facilities for disco. module Disco.Pretty class Pretty t pretty :: (Pretty t, Members '[Reader PA, LFresh] r) => t -> Sem r Doc -- | 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 -> Sem r Doc -- | 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 left of an -- operator (so parentheses can be inserted appropriately, depending on -- the associativity). lt :: Member (Reader PA) r => Sem r Doc -> Sem r Doc -- | 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 -> Sem r Doc -- | 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 -> Sem r Doc prettyStr :: Pretty t => t -> Sem r String pretty' :: Pretty t => t -> Sem r Doc -- | 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 findRep :: Ord a => [a] -> ([a], Int) findRep' :: Ord a => Map a Int -> Int -> [a] -> ([a], Int) -- | 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) -- | The abstract type of documents. A Doc represents a set of -- layouts. A Doc with no occurrences of Union or NoDoc represents just -- one layout. data Doc instance Disco.Pretty.Pretty a => Disco.Pretty.Pretty [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 -- | 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) -- | Message logging framework (e.g. for errors, warnings, etc.) for disco. module Disco.Messages data MessageType Info :: MessageType Warning :: MessageType ErrMsg :: MessageType Debug :: MessageType data Message Message :: MessageType -> Doc -> Message [_messageType] :: Message -> MessageType [_message] :: Message -> Doc messageType :: Lens' Message MessageType message :: Lens' Message Doc handleMsg :: Member (Embed IO) r => (Message -> Bool) -> Message -> Sem r () printMsg :: Member (Embed IO) r => Message -> Sem r () msg :: Member (Output Message) r => MessageType -> Sem r Doc -> Sem r () info :: Member (Output Message) r => Sem r Doc -> Sem r () infoPretty :: (Member (Output Message) r, Pretty t) => t -> Sem r () warn :: Member (Output Message) r => Sem r Doc -> Sem r () debug :: Member (Output Message) r => Sem r Doc -> Sem r () debugPretty :: (Member (Output Message) r, Pretty t) => t -> Sem r () err :: Member (Output Message) r => Sem r Doc -> Sem r () instance GHC.Enum.Bounded Disco.Messages.MessageType instance GHC.Enum.Enum Disco.Messages.MessageType instance GHC.Classes.Ord Disco.Messages.MessageType instance GHC.Classes.Eq Disco.Messages.MessageType instance GHC.Read.Read Disco.Messages.MessageType instance GHC.Show.Show Disco.Messages.MessageType instance GHC.Show.Show Disco.Messages.Message -- | 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 [PrimUOp] :: UOp -> Prim [PrimBOp] :: BOp -> Prim [PrimLeft] :: Prim [PrimRight] :: Prim [PrimSqrt] :: Prim [PrimFloor] :: Prim [PrimCeil] :: Prim [PrimAbs] :: Prim [PrimPower] :: Prim [PrimList] :: Prim [PrimBag] :: Prim [PrimSet] :: Prim [PrimB2C] :: Prim [PrimC2B] :: Prim [PrimUC2B] :: Prim [PrimMapToSet] :: Prim [PrimSetToMap] :: Prim [PrimSummary] :: Prim [PrimVertex] :: Prim [PrimEmptyGraph] :: Prim [PrimOverlay] :: Prim [PrimConnect] :: Prim [PrimInsert] :: Prim [PrimLookup] :: Prim [PrimEach] :: Prim [PrimReduce] :: Prim [PrimFilter] :: Prim [PrimJoin] :: Prim [PrimMerge] :: Prim [PrimIsPrime] :: Prim [PrimFactor] :: Prim [PrimFrac] :: Prim [PrimCrash] :: Prim [PrimUntil] :: Prim [PrimHolds] :: Prim [PrimLookupSeq] :: Prim [PrimExtendSeq] :: 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 -- | 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 -- | 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 -- | 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: -- --
-- (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) -- | Constraint solver for the constraints generated during type -- checking/inference. module Disco.Typecheck.Solve -- | Type of errors which can be generated by the constraint solving -- process. data SolveError [NoWeakUnifier] :: SolveError [NoUnify] :: SolveError [UnqualBase] :: Qualifier -> BaseTy -> SolveError [Unqual] :: Qualifier -> Type -> SolveError [QualSkolem] :: Qualifier -> Name Type -> SolveError runSolve :: Sem (Fresh : (Error SolveError : r)) a -> Sem r (Either SolveError a) -- | Run a list of actions, and return the results from those which do not -- throw an error. If all of them throw an error, rethrow the first one. filterErrors :: Member (Error e) r => [Sem r a] -> Sem r [a] -- | A variant of asum which picks the first action that succeeds, -- or re-throws the error of the last one if none of them do. -- Precondition: the list must not be empty. asum' :: Member (Error e) r => [Sem r a] -> Sem r a data SimpleConstraint [:<:] :: Type -> Type -> SimpleConstraint [:=:] :: Type -> Type -> SimpleConstraint -- | Information about a particular type variable. More information may be -- added in the future (e.g. polarity). data TyVarInfo TVI :: First Ilk -> Sort -> TyVarInfo -- | The ilk (unification or skolem) of the variable, if known [_tyVarIlk] :: TyVarInfo -> First Ilk -- | The sort (set of qualifiers) of the type variable. [_tyVarSort] :: TyVarInfo -> Sort tyVarSort :: Lens' TyVarInfo Sort tyVarIlk :: Lens' TyVarInfo (First Ilk) -- | Create a TyVarInfo given an Ilk and a Sort. mkTVI :: Ilk -> Sort -> TyVarInfo -- | A TyVarInfoMap records what we know about each type variable; -- it is a mapping from type variable names to TyVarInfo records. newtype TyVarInfoMap VM :: Map (Name Type) TyVarInfo -> TyVarInfoMap [unVM] :: TyVarInfoMap -> Map (Name Type) TyVarInfo -- | Utility function for acting on a TyVarInfoMap by acting on the -- underlying Map. onVM :: (Map (Name Type) TyVarInfo -> Map (Name Type) TyVarInfo) -> TyVarInfoMap -> TyVarInfoMap -- | Look up a given variable name in a TyVarInfoMap. lookupVM :: Name Type -> TyVarInfoMap -> Maybe TyVarInfo -- | Remove the mapping for a particular variable name (if it exists) from -- a TyVarInfoMap. deleteVM :: Name Type -> TyVarInfoMap -> TyVarInfoMap -- | Given a list of type variable names, add them all to the -- TyVarInfoMap as Skolem variables (with a trivial sort). addSkolems :: [Name Type] -> TyVarInfoMap -> TyVarInfoMap -- | Get the sort of a particular variable recorded in a -- TyVarInfoMap. Returns the trivial (empty) sort for a variable -- not in the map. getSort :: TyVarInfoMap -> Name Type -> Sort -- | Get the Ilk of a variable recorded in a TyVarInfoMap. -- Returns Nothing if the variable is not in the map, or if its -- ilk is not known. getIlk :: TyVarInfoMap -> Name Type -> Maybe Ilk -- | Extend the sort of a type variable by combining its existing sort with -- the given one. Has no effect if the variable is not already in the -- map. extendSort :: Name Type -> Sort -> TyVarInfoMap -> TyVarInfoMap data SimplifyState SS :: TyVarInfoMap -> [SimpleConstraint] -> S -> Set SimpleConstraint -> SimplifyState [_ssVarMap] :: SimplifyState -> TyVarInfoMap [_ssConstraints] :: SimplifyState -> [SimpleConstraint] [_ssSubst] :: SimplifyState -> S [_ssSeen] :: SimplifyState -> Set SimpleConstraint ssVarMap :: Lens' SimplifyState TyVarInfoMap ssSubst :: Lens' SimplifyState S ssSeen :: Lens' SimplifyState (Set SimpleConstraint) ssConstraints :: Lens' SimplifyState [SimpleConstraint] lkup :: (Ord k, Show k, Show (Map k a)) => String -> Map k a -> k -> a solveConstraint :: Members '[Fresh, Error SolveError, Output Message, Input TyDefCtx] r => Constraint -> Sem r S solveConstraintChoice :: Members '[Fresh, Error SolveError, Output Message, Input TyDefCtx] r => TyVarInfoMap -> [SimpleConstraint] -> Sem r S decomposeConstraint :: Members '[Fresh, Error SolveError, Input TyDefCtx] r => Constraint -> Sem r [(TyVarInfoMap, [SimpleConstraint])] decomposeQual :: Members '[Fresh, Error SolveError, Input TyDefCtx] r => Type -> Qualifier -> Sem r TyVarInfoMap checkQual :: Members '[Fresh, Error SolveError] r => Qualifier -> Atom -> Sem r TyVarInfoMap -- | This step does unification of equality constraints, as well as -- structural decomposition of subtyping constraints. For example, if we -- have a constraint (x -> y) (z - Int), then we can decompose -- it into two constraints, (z <: x) and (y <: Int); if we have a -- constraint v <: (a,b), then we substitute v ↦ (x,y) (where x and y -- are fresh type variables) and continue; and so on. -- -- After this step, the remaining constraints will all be atomic -- constraints, that is, only of the form (v1 <: v2), (v <: b), or -- (b <: v), where v is a type variable and b is a base type. simplify :: Members '[Error SolveError, Output Message, Input TyDefCtx] r => TyVarInfoMap -> [SimpleConstraint] -> Sem r (TyVarInfoMap, [(Atom, Atom)], S) -- | Given a list of atoms and atomic subtype constraints (each pair -- (a1,a2) corresponds to the constraint a1 <: a2) -- build the corresponding constraint graph. mkConstraintGraph :: (Show a, Ord a) => Set a -> [(a, a)] -> Graph a -- | Check for any weakly connected components containing more than one -- skolem, or a skolem and a base type, or a skolem and any variables -- with nontrivial sorts; such components are not allowed. If there are -- any WCCs with a single skolem, no base types, and only unsorted -- variables, just unify them all with the skolem and remove those -- components. checkSkolems :: Members '[Error SolveError, Output Message, Input TyDefCtx] r => TyVarInfoMap -> Graph Atom -> Sem r (Graph UAtom, S) -- | Eliminate cycles in the constraint set by collapsing each strongly -- connected component to a single node, (unifying all the types in the -- SCC). A strongly connected component is a maximal set of nodes where -- every node is reachable from every other by a directed path; since we -- are using directed edges to indicate a subtyping constraint, this -- means every node must be a subtype of every other, and the only way -- this can happen is if all are in fact equal. -- -- Of course, this step can fail if the types in a SCC are not unifiable. -- If it succeeds, it returns the collapsed graph (which is now -- guaranteed to be acyclic, i.e. a DAG) and a substitution. elimCycles :: Members '[Error SolveError] r => TyDefCtx -> Graph UAtom -> Sem r (Graph UAtom, S) elimCyclesGen :: forall a b r. (Subst a a, Ord a, Members '[Error SolveError] r) => (Substitution a -> Substitution b) -> ([a] -> Maybe (Substitution a)) -> Graph a -> Sem r (Graph a, Substitution b) -- | Rels stores the set of base types and variables related to a given -- variable in the constraint graph (either predecessors or successors, -- but not both). data Rels Rels :: Set BaseTy -> Set (Name Type) -> Rels [baseRels] :: Rels -> Set BaseTy [varRels] :: Rels -> Set (Name Type) -- | A RelMap associates each variable to its sets of base type and -- variable predecessors and successors in the constraint graph. newtype RelMap RelMap :: Map (Name Type, Dir) Rels -> RelMap [unRelMap] :: RelMap -> Map (Name Type, Dir) Rels -- | Modify a RelMap to record the fact that we have solved for a -- type variable. In particular, delete the variable from the -- RelMap as a key, and also update the relative sets of every -- other variable to remove this variable and add the base type we chose -- for it. substRel :: Name Type -> BaseTy -> RelMap -> RelMap -- | Essentially dirtypesBySort vm rm dir t s x finds all the dir-types -- (sub- or super-) of t which have sort s, relative to the variables in -- x. This is overbar{T}_S^X (resp. underbar...) from Traytel et al. dirtypesBySort :: TyVarInfoMap -> RelMap -> Dir -> BaseTy -> Sort -> Set (Name Type) -> [BaseTy] -- | Sort-aware infimum or supremum. limBySort :: TyVarInfoMap -> RelMap -> Dir -> [BaseTy] -> Sort -> Set (Name Type) -> Maybe BaseTy lubBySort :: TyVarInfoMap -> RelMap -> [BaseTy] -> Sort -> Set (Name Type) -> Maybe BaseTy glbBySort :: TyVarInfoMap -> RelMap -> [BaseTy] -> Sort -> Set (Name Type) -> Maybe BaseTy -- | From the constraint graph, build the sets of sub- and super- base -- types of each type variable, as well as the sets of sub- and supertype -- variables. For each type variable x in turn, try to find a common -- supertype of its base subtypes which is consistent with the sort of x -- and with the sorts of all its sub-variables, as well as symmetrically -- a common subtype of its supertypes, etc. Assign x one of the two: if -- it has only successors, assign it their inf; otherwise, assign it the -- sup of its predecessors. If it has both, we have a choice of whether -- to assign it the sup of predecessors or inf of successors; both lead -- to a sound & complete algorithm. We choose to assign it the sup of -- its predecessors in this case, since it seems nice to default to -- "simpler" types lower down in the subtyping chain. solveGraph :: Members '[Fresh, Error SolveError, Output Message] r => TyVarInfoMap -> Graph UAtom -> Sem r S instance GHC.Classes.Eq Disco.Typecheck.Solve.Rels instance GHC.Show.Show Disco.Typecheck.Solve.Rels instance Disco.Pretty.Pretty Disco.Typecheck.Solve.RelMap instance GHC.Show.Show Disco.Typecheck.Solve.TyVarInfoMap instance Disco.Pretty.Pretty Disco.Typecheck.Solve.TyVarInfoMap instance GHC.Base.Semigroup Disco.Typecheck.Solve.TyVarInfoMap instance GHC.Base.Monoid Disco.Typecheck.Solve.TyVarInfoMap instance Disco.Pretty.Pretty Disco.Typecheck.Solve.TyVarInfo instance GHC.Base.Semigroup Disco.Typecheck.Solve.TyVarInfo instance GHC.Show.Show Disco.Typecheck.Solve.SolveError instance Unbound.Generics.LocallyNameless.Subst.Subst Disco.Types.Type Disco.Typecheck.Solve.SimpleConstraint instance Unbound.Generics.LocallyNameless.Alpha.Alpha Disco.Typecheck.Solve.SimpleConstraint instance GHC.Generics.Generic Disco.Typecheck.Solve.SimpleConstraint instance GHC.Classes.Ord Disco.Typecheck.Solve.SimpleConstraint instance GHC.Classes.Eq Disco.Typecheck.Solve.SimpleConstraint instance GHC.Show.Show Disco.Typecheck.Solve.SimpleConstraint instance GHC.Show.Show Disco.Typecheck.Solve.TyVarInfo instance Disco.Pretty.Pretty Disco.Typecheck.Solve.SimpleConstraint instance GHC.Base.Semigroup Disco.Typecheck.Solve.SolveError -- | Definition of type contexts, type errors, and various utilities used -- during type checking. module Disco.Typecheck.Util -- | A typing context is a mapping from term names to types. type TyCtx = Ctx Term PolyType -- | A typechecking error, wrapped up together with the name of the thing -- that was being checked when the error occurred. data LocTCError LocTCError :: Maybe (QName Term) -> TCError -> LocTCError -- | Wrap a TCError into a LocTCError with no explicit -- provenance information. noLoc :: TCError -> LocTCError -- | Potential typechecking errors. data TCError -- | Encountered an unbound variable Unbound :: Name Term -> TCError -- | Encountered an ambiguous name. Ambiguous :: Name Term -> [ModuleName] -> TCError -- | No type is specified for a definition NoType :: Name Term -> TCError -- | The type of the term should have an outermost constructor matching -- Con, but it has type Type instead NotCon :: Con -> Term -> Type -> TCError -- | Case analyses cannot be empty. EmptyCase :: TCError -- | The given pattern should have the type, but it doesn't. instead it has -- a kind of type given by the Con. PatternType :: Con -> Pattern -> Type -> TCError -- | Duplicate declarations. DuplicateDecls :: Name Term -> TCError -- | Duplicate definitions. DuplicateDefns :: Name Term -> TCError -- | Duplicate type definitions. DuplicateTyDefns :: String -> TCError -- | Cyclic type definition. CyclicTyDef :: String -> TCError -- | # of patterns does not match type in definition NumPatterns :: TCError -- | Type can't be quantified over. NoSearch :: Type -> TCError -- | The constraint solver couldn't find a solution. Unsolvable :: SolveError -> TCError -- | An undefined type name was used. NotTyDef :: String -> TCError -- | Wildcards are not allowed in terms. NoTWild :: TCError -- | Not enough arguments provided to type constructor. NotEnoughArgs :: Con -> TCError -- | Too many arguments provided to type constructor. TooManyArgs :: Con -> TCError -- | Unbound type variable UnboundTyVar :: Name Type -> TCError -- | Polymorphic recursion is not allowed NoPolyRec :: String -> [String] -> [Type] -> TCError -- | Not an error. The identity of the Monoid TCError instance. NoError :: TCError -- | Emit a constraint. constraint :: Member (Writer Constraint) r => Constraint -> Sem r () -- | Emit a list of constraints. constraints :: Member (Writer Constraint) r => [Constraint] -> Sem r () -- | Close over the current constraint with a forall. forAll :: Member (Writer Constraint) r => [Name Type] -> Sem r a -> Sem r a -- | Run two constraint-generating actions and combine the constraints via -- disjunction. cOr :: Members '[Writer Constraint] r => Sem r () -> Sem r () -> Sem r () -- | Run a computation that generates constraints, returning the generated -- Constraint along with the output. Note that this locally -- dispatches the constraint writer effect. -- -- This function is somewhat low-level; typically you should use -- solve instead, which also solves the generated constraints. withConstraint :: Sem (Writer Constraint : r) a -> Sem r (a, Constraint) -- | Run a computation and solve its generated constraint, returning the -- resulting substitution (or failing with an error). Note that this -- locally dispatches the constraint writer effect. solve :: Members '[Reader TyDefCtx, Error TCError, Output Message] r => Sem (Writer Constraint : r) a -> Sem r (a, S) -- | Look up the definition of a named type. Throw a NotTyDef error -- if it is not found. lookupTyDefn :: Members '[Reader TyDefCtx, Error TCError] r => String -> [Type] -> Sem r Type -- | Run a subcomputation with an extended type definition context. withTyDefns :: Member (Reader TyDefCtx) r => TyDefCtx -> Sem r a -> Sem r a -- | Generate a type variable with a fresh name. freshTy :: Member Fresh r => Sem r Type -- | Generate a fresh variable as an atom. freshAtom :: Member Fresh r => Sem r Atom instance GHC.Show.Show Disco.Typecheck.Util.TCError instance GHC.Show.Show Disco.Typecheck.Util.LocTCError instance GHC.Base.Semigroup Disco.Typecheck.Util.TCError instance GHC.Base.Monoid Disco.Typecheck.Util.TCError -- | Built-in documentation. module Disco.Doc -- | A map from some primitives to a short descriptive string, to be shown -- by the :doc command. primDoc :: Map Prim String -- | A map from some primitives to their corresponding page in the Disco -- language reference -- (https:/disco-lang.readthedocs.ioenlatestreference/index.html). primReference :: Map Prim String otherDoc :: Map String String otherReference :: Map String String -- | The ModuleInfo record representing a disco module, and -- functions to resolve the location of a module on disk. module Disco.Module -- | When loading a module, we could be loading it from code entered at the -- REPL, or from a standalone file. The two modes have slightly different -- behavior. data LoadingMode REPL :: LoadingMode Standalone :: LoadingMode -- | A definition consists of a name being defined, the types of any -- pattern arguments (each clause must have the same number of patterns), -- the type of the body of each clause, and a list of clauses. For -- example, -- --
-- 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 -> [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 -- | 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) -- | 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, 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] 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] 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] 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: infer a (polymorphic) type for a -- term by running type inference, solving the resulting constraints, and -- quantifying over any remaining type variables. inferTop :: Members '[Output Message, Reader TyCtx, Reader TyDefCtx, Error TCError, Fresh] r => Term -> Sem r (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, 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 () instance GHC.Show.Show Disco.Typecheck.Mode -- | Parser to convert concrete Disco syntax into an (untyped, surface -- language) AST. module Disco.Parser data DiscoParseError ReservedVarName :: String -> DiscoParseError InvalidPattern :: OpaqueTerm -> 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
-- ::= '[' container-contents ']'
-- | '{' container-contents '}'
--
-- container-contents
-- ::= empty | nonempty-container
--
-- nonempty-container
-- ::= term [ ellipsis ]
-- | term container-end
--
-- container-end
-- ::= '|' comprehension
-- | ',' [ term (',' item)* ] [ 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. parsePattern :: 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) 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, which also carries a flag saying how fractional -- values should be diplayed. [VNum] :: RationalDisplay -> 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] :: 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 -- | 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] :: RationalDisplay -> 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 -- | A convenience function for creating a default VNum value with -- a default (Fractional) flag. 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 -- | Turn any instance of Enum into a Value, by creating -- a constructor with an index corresponding to the enum value. enumv :: Enum e => e -> Value 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] -- | 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 -- | 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 an equality test. Records the values being compared and -- also their type (which is needed for printing). TestEqual :: 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 -- | 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 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 -- | 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 -- | 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) -- | Set the cell at a given index. set :: Members '[State Mem] r => Int -> Cell -> Sem r () prettyValue' :: Member (Input TyDefCtx) r => Type -> Value -> Sem r Doc prettyValue :: Members '[Input TyDefCtx, LFresh, Reader PA] r => Type -> Value -> Sem r Doc prettyTestFailure :: Members '[Input TyDefCtx, LFresh, Reader PA] r => AProperty -> TestResult -> Sem r Doc prettyTestResult :: Members '[Input TyDefCtx, LFresh, Reader PA] r => AProperty -> TestResult -> Sem r Doc 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.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 -- | Properties of disco functions. module Disco.Property -- | 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 -- | 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) -- | 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]] -- | 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 -- | 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 -- | 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 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, 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, 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, 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] 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] 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, 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.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 ()