-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Educational implementation of the STG (Spineless Tagless -- G-machine) -- -- STGi is a visual STG implementation to help understand Haskell's -- execution model. -- -- It does this by guiding through the running of a program, showing -- stack and heap, and giving explanations of the applied transition -- rules. -- -- Here is what an intermediate state looks like: -- -- -- For further information, see README.md. @package stgi @version 1.1 -- | Useful utilities that don't really fit in a specific location. module Stg.Util -- | show with Text as codomain. -- --
-- show' = pack . show --show' :: Show a => a -> Text -- | Either with an accumulating Applicative instance data Validate err a Failure :: err -> Validate err a Success :: a -> Validate err a -- |
-- [a,b,c] ==> a, b, c --commaSep :: [Doc ann] -> Doc ann instance GHC.Base.Functor (Stg.Util.Validate a) instance Data.Bifunctor.Bifunctor Stg.Util.Validate instance GHC.Base.Monoid a => GHC.Base.Applicative (Stg.Util.Validate a) -- | Prettyprinting STG elements in various formats. module Stg.Language.Prettyprint class PrettyStgi a prettyStgi :: PrettyStgi a => a -> Doc StgiAnn data StgiAnn StateAnn :: StateAnn -> StgiAnn AstAnn :: AstAnn -> StgiAnn -- | Semantic annotations for rendering. data StateAnn -- | Style of headlines in the state overview, such as "Heap" and "Frame -- i". Headline :: StateAnn -- | Style of memory addresses, including 0x prefix. Address :: StateAnn -- | Style of memory addresses; applied only to the actual address number, -- such as ff in 0xff. AddressCore :: StateAnn -- | Style of the type of a closure, such as BLACKHOLE or FUN. ClosureType :: StateAnn -- | Style of the stack frame annotation, such as UPD or ARG. StackFrameType :: StateAnn -- | The different semantic annotations an STG AST element can have. data AstAnn Keyword :: AstAnn Prim :: AstAnn Variable :: AstAnn Constructor :: AstAnn Semicolon :: AstAnn renderRich :: Doc StgiAnn -> Text renderPlain :: Doc ann -> Text -- | Prettyprint a value as Text, including styles such as colours. prettyprintOldAnsi :: Doc -> Text instance Stg.Language.Prettyprint.PrettyStgi GHC.Types.Bool instance Stg.Language.Prettyprint.PrettyStgi GHC.Types.Int instance Stg.Language.Prettyprint.PrettyStgi GHC.Integer.Type.Integer instance (Stg.Language.Prettyprint.PrettyStgi a, Stg.Language.Prettyprint.PrettyStgi b) => Stg.Language.Prettyprint.PrettyStgi (a, b) instance Stg.Language.Prettyprint.PrettyStgi a => Stg.Language.Prettyprint.PrettyStgi [a] -- | The STG language syntax tree, modeled after the description in the -- 1992 paper (link). -- -- A Program is typically created using functionality provided by -- the Stg.Parser module, as opposed to manually combining the -- data types given in this module. -- -- For plenty of comparisons of STG language source and generated parse -- trees, have a look at the Stg.Parser.QuasiQuoter module. module Stg.Language -- | An STG Program is the unit that can be loaded by the STG -- machine. It consists of a set of bindings. newtype Program Program :: Binds -> Program -- | Bindings are collections of lambda forms, indexed over variables. -- -- They exist at the top level, or as part of a let(rec) binding. newtype Binds Binds :: (Map Var LambdaForm) -> Binds -- | A lambda form unifies free and bound variables associated with a -- function body. The lambda body must not be of primitive type, as this -- would imply the value is both boxed and unboxed. -- --
-- >>> [stg| \(x) y z -> expr x z |] -- LambdaForm [Var "x"] NoUpdate [Var "y",Var "z"] (AppF (Var "expr") [AtomVar (Var "x"),AtomVar (Var "z")]) --data LambdaForm -- |
-- + --Add :: PrimOp -- |
-- - --Sub :: PrimOp -- |
-- * --Mul :: PrimOp -- |
-- / --Div :: PrimOp -- |
-- % --Mod :: PrimOp -- |
-- == --Eq :: PrimOp -- |
-- < --Lt :: PrimOp -- |
-- <= --Leq :: PrimOp -- |
-- > --Gt :: PrimOp -- |
-- >= --Geq :: PrimOp -- |
-- /= --Neq :: PrimOp -- | Variable. newtype Var Var :: Text -> Var -- | Smallest unit of data. Atoms unify variables and literals, and are -- what functions take as arguments. data Atom AtomVar :: !Var -> Atom AtomLit :: !Literal -> Atom -- | Constructors of algebraic data types. newtype Constr Constr :: Text -> Constr -- | Overloaded conversion to Doc. -- -- Laws: -- --
-- >>> pretty 1 <+> pretty "hello" <+> pretty 1.234 -- 1 hello 1.234 --pretty :: Pretty a => a -> Doc ann -- | prettyList is only used to define the instance -- Pretty a => Pretty [a]. In normal circumstances -- only the pretty function is used. -- --
-- >>> prettyList [1, 23, 456] -- [1, 23, 456] --prettyList :: Pretty a => [a] -> Doc ann -- | Classify the type of a lambda form based on its shape. classify :: LambdaForm -> LambdaType -- | Possible classification of lambda forms. data LambdaType -- | Data constructor (AppC as body) LambdaCon :: LambdaType -- | Function (lambda with non-empty argument list) LambdaFun :: LambdaType -- | Thunk (everything else) LambdaThunk :: LambdaType instance Language.Haskell.TH.Syntax.Lift Stg.Language.Program instance Language.Haskell.TH.Syntax.Lift Stg.Language.Literal instance Language.Haskell.TH.Syntax.Lift Stg.Language.LambdaForm instance Language.Haskell.TH.Syntax.Lift Stg.Language.UpdateFlag instance Language.Haskell.TH.Syntax.Lift Stg.Language.Rec instance Language.Haskell.TH.Syntax.Lift Stg.Language.Expr instance Language.Haskell.TH.Syntax.Lift Stg.Language.Alts instance Language.Haskell.TH.Syntax.Lift Stg.Language.AlgebraicAlt instance Language.Haskell.TH.Syntax.Lift Stg.Language.PrimitiveAlt instance Language.Haskell.TH.Syntax.Lift Stg.Language.DefaultAlt instance Language.Haskell.TH.Syntax.Lift Stg.Language.PrimOp instance Language.Haskell.TH.Syntax.Lift Stg.Language.Atom instance Language.Haskell.TH.Syntax.Lift Stg.Language.NonDefaultAlts instance Language.Haskell.TH.Syntax.Lift Stg.Language.Binds instance Language.Haskell.TH.Syntax.Lift Stg.Language.Constr instance Language.Haskell.TH.Syntax.Lift Stg.Language.Var instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Program instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Binds instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.LambdaForm instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Rec instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Expr instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Alts instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.AlgebraicAlt instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.PrimitiveAlt instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.DefaultAlt instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Literal instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.PrimOp instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Var instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Atom instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.Constr instance Control.DeepSeq.NFData Stg.Language.Program instance Control.DeepSeq.NFData Stg.Language.Binds instance Control.DeepSeq.NFData Stg.Language.LambdaForm instance Control.DeepSeq.NFData Stg.Language.UpdateFlag instance Control.DeepSeq.NFData Stg.Language.Rec instance Control.DeepSeq.NFData Stg.Language.Expr instance Control.DeepSeq.NFData Stg.Language.Alts instance Control.DeepSeq.NFData Stg.Language.NonDefaultAlts instance Control.DeepSeq.NFData Stg.Language.AlgebraicAlt instance Control.DeepSeq.NFData Stg.Language.PrimitiveAlt instance Control.DeepSeq.NFData Stg.Language.DefaultAlt instance Control.DeepSeq.NFData Stg.Language.Literal instance Control.DeepSeq.NFData Stg.Language.PrimOp instance Control.DeepSeq.NFData Stg.Language.Var instance Control.DeepSeq.NFData Stg.Language.Atom instance Control.DeepSeq.NFData Stg.Language.Constr instance GHC.Generics.Generic Stg.Language.Program instance GHC.Show.Show Stg.Language.Program instance GHC.Classes.Ord Stg.Language.Program instance GHC.Classes.Eq Stg.Language.Program instance GHC.Generics.Generic Stg.Language.LambdaForm instance GHC.Show.Show Stg.Language.LambdaForm instance GHC.Classes.Ord Stg.Language.LambdaForm instance GHC.Classes.Eq Stg.Language.LambdaForm instance GHC.Generics.Generic Stg.Language.Binds instance GHC.Classes.Ord Stg.Language.Binds instance GHC.Classes.Eq Stg.Language.Binds instance GHC.Generics.Generic Stg.Language.AlgebraicAlt instance GHC.Show.Show Stg.Language.AlgebraicAlt instance GHC.Classes.Ord Stg.Language.AlgebraicAlt instance GHC.Classes.Eq Stg.Language.AlgebraicAlt instance GHC.Generics.Generic Stg.Language.PrimitiveAlt instance GHC.Show.Show Stg.Language.PrimitiveAlt instance GHC.Classes.Ord Stg.Language.PrimitiveAlt instance GHC.Classes.Eq Stg.Language.PrimitiveAlt instance GHC.Generics.Generic Stg.Language.NonDefaultAlts instance GHC.Show.Show Stg.Language.NonDefaultAlts instance GHC.Classes.Ord Stg.Language.NonDefaultAlts instance GHC.Classes.Eq Stg.Language.NonDefaultAlts instance GHC.Generics.Generic Stg.Language.DefaultAlt instance GHC.Show.Show Stg.Language.DefaultAlt instance GHC.Classes.Ord Stg.Language.DefaultAlt instance GHC.Classes.Eq Stg.Language.DefaultAlt instance GHC.Generics.Generic Stg.Language.Alts instance GHC.Show.Show Stg.Language.Alts instance GHC.Classes.Ord Stg.Language.Alts instance GHC.Classes.Eq Stg.Language.Alts instance GHC.Generics.Generic Stg.Language.Expr instance GHC.Show.Show Stg.Language.Expr instance GHC.Classes.Ord Stg.Language.Expr instance GHC.Classes.Eq Stg.Language.Expr instance GHC.Generics.Generic Stg.Language.Constr instance GHC.Show.Show Stg.Language.Constr instance GHC.Classes.Ord Stg.Language.Constr instance GHC.Classes.Eq Stg.Language.Constr instance GHC.Generics.Generic Stg.Language.Atom instance GHC.Show.Show Stg.Language.Atom instance GHC.Classes.Ord Stg.Language.Atom instance GHC.Classes.Eq Stg.Language.Atom instance GHC.Generics.Generic Stg.Language.Var instance GHC.Show.Show Stg.Language.Var instance GHC.Classes.Ord Stg.Language.Var instance GHC.Classes.Eq Stg.Language.Var instance GHC.Enum.Enum Stg.Language.PrimOp instance GHC.Enum.Bounded Stg.Language.PrimOp instance GHC.Generics.Generic Stg.Language.PrimOp instance GHC.Show.Show Stg.Language.PrimOp instance GHC.Classes.Ord Stg.Language.PrimOp instance GHC.Classes.Eq Stg.Language.PrimOp instance GHC.Generics.Generic Stg.Language.Literal instance GHC.Show.Show Stg.Language.Literal instance GHC.Classes.Ord Stg.Language.Literal instance GHC.Classes.Eq Stg.Language.Literal instance GHC.Enum.Bounded Stg.Language.Rec instance GHC.Enum.Enum Stg.Language.Rec instance GHC.Generics.Generic Stg.Language.Rec instance GHC.Show.Show Stg.Language.Rec instance GHC.Classes.Ord Stg.Language.Rec instance GHC.Classes.Eq Stg.Language.Rec instance GHC.Enum.Bounded Stg.Language.UpdateFlag instance GHC.Enum.Enum Stg.Language.UpdateFlag instance GHC.Generics.Generic Stg.Language.UpdateFlag instance GHC.Show.Show Stg.Language.UpdateFlag instance GHC.Classes.Ord Stg.Language.UpdateFlag instance GHC.Classes.Eq Stg.Language.UpdateFlag instance GHC.Show.Show Stg.Language.LambdaType instance GHC.Classes.Ord Stg.Language.LambdaType instance GHC.Classes.Eq Stg.Language.LambdaType instance GHC.Base.Monoid Stg.Language.Program instance Data.Semigroup.Semigroup Stg.Language.Program instance GHC.Base.Monoid Stg.Language.Binds instance Data.Semigroup.Semigroup Stg.Language.Binds instance GHC.Show.Show Stg.Language.Binds instance Stg.Language.Prettyprint.PrettyStgi Stg.Language.LambdaType instance Data.String.IsString Stg.Language.Var instance Data.String.IsString Stg.Language.Constr -- | Definitions useful for all state transition modules. module Stg.Machine.Evaluate.Common -- | Possible errors of primops data PrimError -- | Division by zero Div0 :: PrimError -- | Apply a primop to two actual integers applyPrimOp :: PrimOp -> Integer -> Integer -> Validate PrimError Integer -- | Successful alternative match, used for finding the right branch in -- case data AltMatch alt AltMatches :: alt -> AltMatch alt DefaultMatches :: DefaultAlt -> AltMatch alt -- | Possible errors when looking up alternatives data AltError -- | Algebraic/primitive alternative in primitive/algebraic case BadAlt :: AltError -- | Look up an algebraic constructor among the given alternatives, and -- return the first match. If nothing matches, return the default -- alternative. lookupAlgebraicAlt :: Alts -> Constr -> Validate AltError (AltMatch AlgebraicAlt) -- | lookupAlgebraicAlt for primitive literals. lookupPrimitiveAlt :: Alts -> Literal -> Validate AltError (AltMatch PrimitiveAlt) -- | A parser for the STG language, modeled after the grammar given in the -- description in the 1992 paper (link) with a couple of -- differences to enhance usability: -- --
-- >>> parse program "id = \\x -> x" -- Right (Program (Binds [(Var "id",LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []))])) --parse :: StgParser ast -> Text -> Either Doc ast -- | A parser for an STG syntax element. data StgParser ast -- | Parse an STG program. program :: StgParser Program -- | Parse a collection of bindings, used by let(rec) expressions -- and at the top level of a program. binds :: StgParser Binds -- | Parse a lambda form, consisting of a list of free variables, and -- update flag, a list of bound variables, and the function body. lambdaForm :: StgParser LambdaForm -- | Parse an expression, which can be -- --
-- Nil -> ... -- Cons x xs -> ... ---- --
-- 1# -> ... -- 2# -> ... --nonDefaultAlts :: StgParser NonDefaultAlts -- | Parse a single algebraic alternative. -- --
-- Cons x xs -> ... --algebraicAlt :: StgParser AlgebraicAlt -- | Parse a single primitive alternative, such as 1#. -- --
-- 1# -> ... --primitiveAlt :: StgParser PrimitiveAlt -- | Parse the default alternative, taken if none of the other alternatives -- in a case expression match. -- --
-- default -> ... ---- --
-- v -> ... --defaultAlt :: StgParser DefaultAlt -- | Parse an integer literal -- --
-- 1# -- -123# --literal :: StgParser Literal -- | Parse a primitive operation. -- --
-- +# --primOp :: StgParser PrimOp -- | Parse an atom atom :: StgParser Atom -- | Parse a variable identifier. Variables start with a lower-case letter -- or _, followed by a string consisting of alphanumeric -- characters or ', _. var :: StgParser Var -- | Parse a constructor identifier. Constructors follow the same naming -- conventions as variables, but start with an upper-case character -- instead, and may end with a # symbol. con :: StgParser Constr instance GHC.Base.Monad Stg.Parser.Parser.StgParser instance GHC.Base.Functor Stg.Parser.Parser.StgParser instance GHC.Base.Applicative Stg.Parser.Parser.StgParser instance GHC.Base.Alternative Stg.Parser.Parser.StgParser instance Text.Parser.Combinators.Parsing Stg.Parser.Parser.StgParser instance Text.Parser.Char.CharParsing Stg.Parser.Parser.StgParser instance Text.Parser.Token.TokenParsing Stg.Parser.Parser.StgParser -- | Quasiquoters for easier generation of STG syntax trees. The stg -- quoter is most convenient, I suggest you use it unless you have a -- reason not to. module Stg.Parser.QuasiQuoter -- | Heuristic quasiquoter for STG language elements. Tries a number of -- parsers, and will use the first successful one. -- -- To gain more fine-grained control over what the input should be parsed -- to, use one of the non-heuristic quoters, such as stgProgram -- or stgLambdaForm. These will also give you much better error -- messages than merely "doesn't work". -- --
-- >>> [stg| id = \x -> x |] -- Program (Binds [(Var "id",LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []))]) ---- --
-- >>> [stg| \x -> x |] -- LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []) ---- --
-- >>> [stg| x |] -- AppF (Var "x") [] --stg :: QuasiQuoter -- | Quasiquoter for Programs. -- --
-- >>> [program| id = \x -> x |] -- Program (Binds [(Var "id",LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []))]) --program :: QuasiQuoter -- | Quasiquoter for Binds. -- --
-- >>> [binds| id = \x -> x |] -- (Binds [(Var "id",LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []))]) --binds :: QuasiQuoter -- | Quasiquoter for LambdaForms. -- --
-- >>> [lambdaForm| \x -> x |] -- LambdaForm [] NoUpdate [Var "x"] (AppF (Var "x") []) --lambdaForm :: QuasiQuoter -- | Quasiquoter for Expressions. -- --
-- >>> [expr| f x y z |] -- AppF (Var "f") [AtomVar (Var "x"),AtomVar (Var "y"),AtomVar (Var "z")] --expr :: QuasiQuoter -- | Quasiquoter for Alts. -- --
-- >>> [alts| Just x -> True; default -> False |] -- Alts (AlgebraicAlts (AlgebraicAlt (Constr "Just") [Var "x"] (AppC (Constr "True") []) :| [])) (DefaultNotBound (AppC (Constr "False") [])) ---- --
-- >>> [alts| 0# -> True; default -> False |] -- Alts (PrimitiveAlts (PrimitiveAlt (Literal 0) (AppC (Constr "True") []) :| [])) (DefaultNotBound (AppC (Constr "False") [])) --alts :: QuasiQuoter -- | Quasiquoter for Alt. -- --
-- >>> [nonDefaultAlts| Just x -> True; Nothing -> False; |] -- AlgebraicAlts (AlgebraicAlt (Constr "Just") [Var "x"] (AppC (Constr "True") []) :| [AlgebraicAlt (Constr "Nothing") [] (AppC (Constr "False") [])]) ---- --
-- >>> [nonDefaultAlts| 0# -> False; 1# -> True; |] -- PrimitiveAlts (PrimitiveAlt (Literal 0) (AppC (Constr "False") []) :| [PrimitiveAlt (Literal 1) (AppC (Constr "True") [])]) --nonDefaultAlts :: QuasiQuoter -- | Quasiquoter for AlgebraicAlts. -- --
-- >>> [algebraicAlt| Just x -> x; |] -- AlgebraicAlt (Constr "Just") [Var "x"] (AppF (Var "x") []) --algebraicAlt :: QuasiQuoter -- | Quasiquoter for PrimitiveAlts. -- --
-- >>> [primitiveAlt| 1# -> x; |] -- PrimitiveAlt (Literal 1) (AppF (Var "x") []) --primitiveAlt :: QuasiQuoter -- | Quasiquoter for DefaultAlts. -- --
-- >>> [defaultAlt| default -> x |] -- DefaultNotBound (AppF (Var "x") []) ---- --
-- >>> [defaultAlt| x -> x |] -- DefaultBound (Var "x") (AppF (Var "x") []) --defaultAlt :: QuasiQuoter -- | Quasiquoter for Literals. -- --
-- >>> [literal| 1# |] -- Literal 1 --literal :: QuasiQuoter -- | Quasiquoter for PrimOps. -- --
-- >>> [primOp| +# |] -- Add --primOp :: QuasiQuoter -- | Quasiquoter for Atoms. -- --
-- >>> [atom| x |] -- AtomVar (Var "x") --atom :: QuasiQuoter -- | Boolean functions, like in Data.Bool. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.Bool -- | Binary and. Haskell's (&&). -- --
-- && : Bool -> Bool -> Bool --and2 :: Program -- | Binary or. Haskell's (||). -- --
-- || : Bool -> Bool -> Bool --or2 :: Program -- | Binary negation. -- --
-- not : Bool -> Bool --not :: Program -- | Boolean deconstructor. -- --
-- bool f _ False = f -- bool _ t True = t ---- --
-- bool : a -> a -> Bool -> a --bool :: Program -- | Boolean equality. eq_Bool :: Program -- | Definitions found in Haskell's Data.Function. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.Function -- | Finally I can define seq directly! :-) -- -- Note that this function is less powerful than GHC's seq, since -- STG does not have a rule to force functions, only expressions that -- reduce to an algebraic or primitive value. This leads to the fact that -- STG's seq is less powerful than Haskell's, since in Haskell -- --
-- seq (const ()) () = () ---- -- whereas in the STG -- --
-- constUnit = (x) -> Unit (); -- seq (constUnit, Unit) = ERROR --seq :: Program -- | Identity function. -- --
-- id : a -> a --id :: Program -- | Constant function. -- --
-- Const : a -> b -> a --const :: Program -- | Function composition. -- --
-- compose : (b -> c) -> (a -> b) -> a -> c --compose :: Program -- | The fixed point combinator. -- --
-- fix : (a -> a) -> a --fix :: Program -- | Functions as found in Haskell's Data.Maybe module. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.Maybe -- | Nothing as a top-level closure. -- --
-- nothing : Maybe a --nothing :: Program -- | Deconstructor of the Maybe type. -- --
-- maybe : b -> (a -> b) -> Maybe a -> b --maybe :: Program -- | Operations on boxed integers. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.Number -- | Binary addition of boxed integers add :: Program -- | Difference of boxed integers sub :: Program -- | Binary multiplication of boxed integers mul :: Program -- | Boxed integer division div :: Program -- | Boxed integer modulo operator mod :: Program -- | Equality of boxed integers eq_Int :: Program -- | Less-than for boxed integers lt_Int :: Program -- | Less-or-equal for boxed integers leq_Int :: Program -- | Greater-than for boxed integers gt_Int :: Program -- | Greater-or-equal for boxed integers geq_Int :: Program -- | Inequality of boxed integers neq_Int :: Program -- | Minimum of two boxed integers min :: Program -- | Maximum of two boxed integers max :: Program -- | Definitions found in Haskell's Data.List. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.List -- | The empty list as a top-level closure. -- --
-- nil : [a] --nil :: Program -- | Concatenate two lists. Haskell's (++). -- --
-- concat2 : [a] -> [a] -> [a] --concat2 :: Program -- | reverse a list. -- --
-- reverse [1,2,3] = [3,2,1] ---- --
-- reverse : [a] -> [a] --reverse :: Program -- | Lazy left list fold. Provided mostly for seeing how it causes stack -- overflows. -- --
-- foldl : (b -> a -> b) -> b -> [a] -> b --foldl :: Program -- | Strict left list fold. -- -- Careful: the STG only supports primitive and algebraic case -- scrutinees. As a result, you can only hand primitive or algebraic -- b values to this function or it will fail! -- --
-- foldl' : (b -> a -> b) -> b -> [a] -> b --foldl' :: Program -- | Right list fold. -- --
-- foldr : (a -> b -> b) -> b -> [a] -> b --foldr :: Program -- | Build a list by repeatedly applying a function to an initial value. -- --
-- iterate f x = [x, f x, f (f x), ...] ---- --
-- iterate : (a -> a) -> a -> [a] --iterate :: Program -- | Infinite list created by repeating an initial (non-empty) list. -- --
-- cycle [x,y,z] = [x,y,z, x,y,z, x,y,z, ...] ---- --
-- cycle : [a] -> [a] --cycle :: Program -- | Take n elements form the beginning of a list. -- --
-- take 3 [1..] = [1,2,3] ---- --
-- take : Int -> [a] -> [a] --take :: Program -- | Keep only the elements for which a predicate holds. -- --
-- filter even [1..] = [2, 4, 6, ...] ---- --
-- filter : (a -> Bool) -> [a] -> [a] --filter :: Program -- | Separate a list into parts that do and do not satisfy a predicate. -- --
-- partition even [1..6] = ([2,4,6], [1,3,5]) ---- --
-- partition : (a -> Bool) -> [a] -> ([a], [a]) --partition :: Program -- | Repeat a single element infinitely. -- --
-- repeat 1 = [1, 1, 1, ...] ---- --
-- repeat : a -> [a] --repeat :: Program -- | Repeat a single element a number of times. -- --
-- replicate 3 1 = [1, 1, 1] ---- --
-- replicate : Int -> a -> [a] --replicate :: Program -- | Haskell's Prelude sort function at the time of implementing this. Not -- quite as pretty as the Haskell version, but functionally equivalent. -- :-) -- -- This implementation is particularly efficient when the input contains -- runs of already sorted elements. For comparison, sorting [1..100] -- takes 6496 steps, whereas naiveSort requires 268082. -- --
-- sort : [Int] -> [Int] --sort :: Program -- | That Haskell sort function often misleadingly referred to as -- "quicksort". -- --
-- naiveSort : [Int] -> [Int] --naiveSort :: Program -- | Apply a function to each element of a list. -- --
-- map : (a -> b) -> [a] -> [b] --map :: Program -- | Equality of lists of integers. -- --
-- equals_List_Int : [Int] -> [Int] -> Bool --equals_List_Int :: Program -- | Length of a list. -- --
-- length : [a] -> Int --length :: Program -- | Zip two lists into one. If one list is longer than the other ignore -- the exceeding elements. -- --
-- zip [1,2,3,4,5] [10,20,30] ==> [(1,10),(2,20),(3,30)] -- -- zip xs ys = zipWith Pair xs ys ---- --
-- zip : [a] -> [b] -> [(a,b)] --zip :: Program -- | Zip two lists into one using a user-specified combining function. If -- one list is longer than the other ignore the exceeding elements. -- --
-- zipWith (+) [1,2,3,4,5] [10,20,30] ==> [11,22,33] -- -- zipWith f xs ys = map f (zip xs ys) ---- --
-- zipWith : (a -> b -> c) -> [a] -> [b] -> [c] --zipWith :: Program -- | Force the spine of a list. -- --
-- forceSpine :: [a] -> [a] --forceSpine :: Program -- | Convert Haskell values to STG values. module Stg.Marshal.ToStg -- | Convert a Haskell value to an STG binding. -- -- Instances of this class should have a corresponding FromStg -- instance to retrieve a value fom the program, with the two being -- inverse to each other (up to forcing the generated thunks). -- -- This class contains a helper function, toStgWithGlobals, this -- is hidden from the outside. If you want to write your own instance, -- have a look at the source for documentation. class ToStg value where toStg var val = let (globals, actualDef) = runWriter (toStgWithGlobals var val) in globals <> actualDef toStgWithGlobals var val = pure (toStg var val) toStg :: ToStg value => Var -> value -> Program -- | Some definitions, such as the one for lists, require certain global -- values to be present (such as nil). In order to avoid duplicate -- definitions, this function allows defining top-level elements using -- Writers tell function. toStgWithGlobals :: ToStg value => Var -> value -> Writer Program Program instance Stg.Marshal.ToStg.ToStg () instance Stg.Marshal.ToStg.ToStg GHC.Integer.Type.Integer instance Stg.Marshal.ToStg.ToStg GHC.Types.Int instance Stg.Marshal.ToStg.ToStg GHC.Types.Bool instance Stg.Marshal.ToStg.ToStg a => Stg.Marshal.ToStg.ToStg (GHC.Base.Maybe a) instance (Stg.Marshal.ToStg.ToStg a, Stg.Marshal.ToStg.ToStg b) => Stg.Marshal.ToStg.ToStg (Data.Either.Either a b) instance Stg.Marshal.ToStg.ToStg a => Stg.Marshal.ToStg.ToStg [a] instance (Stg.Marshal.ToStg.ToStg a, Stg.Marshal.ToStg.ToStg b) => Stg.Marshal.ToStg.ToStg (a, b) instance (Stg.Marshal.ToStg.ToStg a, Stg.Marshal.ToStg.ToStg b, Stg.Marshal.ToStg.ToStg c) => Stg.Marshal.ToStg.ToStg (a, b, c) instance (Stg.Marshal.ToStg.ToStg a, Stg.Marshal.ToStg.ToStg b, Stg.Marshal.ToStg.ToStg c, Stg.Marshal.ToStg.ToStg d) => Stg.Marshal.ToStg.ToStg (a, b, c, d) instance (Stg.Marshal.ToStg.ToStg a, Stg.Marshal.ToStg.ToStg b, Stg.Marshal.ToStg.ToStg c, Stg.Marshal.ToStg.ToStg d, Stg.Marshal.ToStg.ToStg e) => Stg.Marshal.ToStg.ToStg (a, b, c, d, e) -- | Definitions found in Haskell's Data.Tuple. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude.Tuple -- | First element of a tuple. -- --
-- fst : (a,b) -> a --fst :: Program -- | Second element of a tuple. -- --
-- snd : (a,b) -> a --snd :: Program -- | Convert an uncurried function to a curried one. -- --
-- curry : ((a, b) -> c) -> a -> b -> c --curry :: Program -- | Convert a curried function to an uncurried one. -- --
-- uncurry : (a -> b -> c) -> (a, b) -> c --uncurry :: Program -- | Swap the elements of a tuple. -- --
-- swap : (a,b) -> (b,a) --swap :: Program -- | Equality of pairs of boxed integers. equals_Pair_Int :: Program -- | Common Haskell functions, translated to STG. Use the Monoid -- instance for Program to mix them. -- -- This module should be imported qualified to avoid clashes with -- standard Haskell definitions. module Stg.Prelude -- | Force a value to normal form and return it. -- -- This function makes heavy use of the fact that the STG is untyped. It -- currently supports the following types: -- --
-- name (state -> (addresses, addresses, state) --GarbageCollectionAlgorithm :: Text -> (StgState -> (Set MemAddr, Map MemAddr MemAddr, StgState)) -> GarbageCollectionAlgorithm -- | Collect all mentioned addresses in a machine element. -- -- Note that none of the types in Stg.Language contain addresses, -- since an address is not something present in the STG language, -- only in the execution contest the language is put in in the -- Stg.Machine modules. class Addresses a where addrs = nubSeq . addrs' -- | All contained addresses in the order they appear, but without -- duplicates. addrs :: Addresses a => a -> Seq MemAddr -- | Update all contained addresses in a certain value. Useful for moving -- garbage collectors. class UpdateAddrs a updateAddrs :: UpdateAddrs a => (MemAddr -> MemAddr) -> a -> a instance (Data.Foldable.Foldable f, Stg.Machine.GarbageCollection.Common.Addresses a) => Stg.Machine.GarbageCollection.Common.Addresses (f a) instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.Code instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.StackFrame instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.MemAddr instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.Globals instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.Locals instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.Closure instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.HeapObject instance Stg.Machine.GarbageCollection.Common.Addresses Stg.Machine.Types.Value instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.Code instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.Locals instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.Globals instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.Value instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.MemAddr instance (GHC.Base.Functor f, Stg.Machine.GarbageCollection.Common.UpdateAddrs a) => Stg.Machine.GarbageCollection.Common.UpdateAddrs (f a) instance Stg.Machine.GarbageCollection.Common.UpdateAddrs Stg.Machine.Types.StackFrame -- | Tri-state ("tri-colour") garbage collector. -- --
-- case 1# of one -> case 2# of two -> case +# one two of ... ---- -- which is a bit silly. I think this might be an oversight in the 1992 -- paper. The fast curry paper does not seem to impose this restriction. -- -- This rule is shadowed by rule1819_casePrimopShortcut, which -- handles primitive application more efficiently, without the need for -- an intermediate ReturnInt state. rule14_primop :: StgState -> Maybe StgState -- | Rule 15: Enter updatable closure -- -- Evaluate the address pointed to, and store its future update in an -- UpdateFrame. -- -- In theory this could just do what rule2_enterNonUpdatable does, -- plus the update frame. However, since lambda forms that take arguments -- never form updatable closures, there is no need for -- ArgumentFrame handling in this rule. rule15_enterUpdatable :: StgState -> Maybe StgState -- | Rule 16: Update because of missing ReturnFrame -- -- A ReturnCon state requires a ReturnFrame to continue, -- but there is an UpdateFrame in the way. The latter has to be -- eliminated by performing an update with the returned constructor -- before attempting the return once more. rule16_missingReturnUpdate :: StgState -> Maybe StgState -- | Rule 17: Enter partially applied closure, update because of missing -- ArgumentFrame -- -- There are not enough ArgFrames on the stack for a lambda's -- arguments, because an update frame blocks access to more. -- -- Although this rule is a bit simpler to understand compared to rule -- 17a, it is hard to implement in a real STG compiler, since a new -- closure has to be made up during runtime, which means runtime code -- generation. Rule 17a remedies this problem. This rule (17) is included -- for comparison anyway. rule17_missingArgUpdate :: StgState -> Maybe StgState -- | Rule 17a: Enter partially applied closure, update because of missing -- ArgumentFrame -- -- This is a better version of rule 17, since it does not neccessitate -- runtime code generation. All required closures can be precompiled. rule17a_missingArgUpdate :: StgState -> Maybe StgState -- | Rules 18, 19: Shortcut for evaluating/matching primops -- -- This rule allows evaluating primops without the overhead of allocating -- an intermediate return stack frame. In order to trigger, it must be -- applied with higher precedence than rule4_case. -- -- When reading the source here for educational purposes, you should skip -- this rule until you've seen the normal case rule (rule4_case) -- and the normal primop rule (rule14_primop). -- -- This rule has the slight modification compared to the paper in that it -- works for both bound and unbound default cases. rule1819_casePrimopShortcut :: StgState -> Maybe StgState -- | Evaluate STG Programs. module Stg.Machine.Evaluate -- | Perform a single STG machine evaluation step. evalStep :: StgState -> StgState -- | Two space stop-and-copy garbage collector. -- --
-- last (evalsUntil ...) ≡ evalUntil --evalUntil :: RunForSteps -> HaltIf -> PerformGc -> StgState -> StgState -- | Evaluate the STG, and record all intermediate states. -- --
-- evalsUntil ≈ unfoldr evalUntil --evalsUntil :: RunForSteps -> HaltIf -> PerformGc -> StgState -> NonEmpty StgState -- | Check whether a state is terminal. terminated :: StgState -> Bool -- | Predicate to decide whether the machine should halt. newtype HaltIf HaltIf :: (StgState -> Bool) -> HaltIf -- | Predicate to decide whether the machine should halt. data RunForSteps -- | Do not terminate based on the number of steps RunIndefinitely :: RunForSteps RunForMaxSteps :: Integer -> RunForSteps -- | Apply a garbage collection algorithm to the heap of the current -- machine state, and return the resulting cleaned state. garbageCollect :: GarbageCollectionAlgorithm -> StgState -> StgState -- | Decide whether garbage collection should be attempted, and with which -- algorithm. newtype PerformGc PerformGc :: (StgState -> Maybe GarbageCollectionAlgorithm) -> PerformGc -- | A garbage collection algorithm is a specific way to get rid of unused -- heap objects. data GarbageCollectionAlgorithm -- | Remove all unused addresses, without moving the others. triStateTracing :: GarbageCollectionAlgorithm -- | Move all used addresses by moving them to a safe location, and delete -- the leftovers. twoSpaceCopying :: GarbageCollectionAlgorithm instance GHC.Show.Show Stg.Machine.AttemptGc instance GHC.Classes.Ord Stg.Machine.AttemptGc instance GHC.Classes.Eq Stg.Machine.AttemptGc -- | Extract Haskell values from running STG programs. module Stg.Marshal.FromStg -- | Look up the value of a global variable. -- -- Instances of this class should have a corresponding ToStg -- instance to inject a value into the program, with the two being -- inverse to each other (up to forcing the generated thunks). class FromStg value where fromStg stgState = globalVal stgState (\case { PrimInt {} -> Left TypeMismatch Addr addr -> fromStgAddr stgState addr }) fromStgPrim _ = Left TypeMismatch -- | Retrieve the value of a global variable. fromStg :: FromStg value => StgState -> Var -> Either FromStgError value -- | Retrieve the value of a heap address. fromStgAddr :: FromStg value => StgState -> MemAddr -> Either FromStgError value -- | Used only for looking up primitive integers. fromStgPrim :: FromStg value => Integer -> Either FromStgError value -- | Classifies the different errors that can happen when extracting a -- value from an STG state. data FromStgError -- | e.g. asking for an Int# at an address that contains a -- Cons TypeMismatch :: FromStgError -- | Tried retrieving a non-constructor IsWrongLambdaType :: LambdaType -> FromStgError -- | Tried retrieving a black hole IsBlackhole :: FromStgError -- | e.g. Cons x y z BadArity :: FromStgError -- | An unsuccessful variable lookup NotFound :: NotInScope -> FromStgError AddrNotOnHeap :: FromStgError -- | None of the given alternatives matched the given constructor, e.g. -- when trying to receive a Left as a Just NoConstructorMatch :: FromStgError instance GHC.Show.Show Stg.Marshal.FromStg.FromStgError instance GHC.Classes.Ord Stg.Marshal.FromStg.FromStgError instance GHC.Classes.Eq Stg.Marshal.FromStg.FromStgError instance Stg.Marshal.FromStg.FromStg () instance Stg.Marshal.FromStg.FromStg GHC.Types.Bool instance Stg.Marshal.FromStg.FromStg GHC.Integer.Type.Integer instance (Stg.Marshal.FromStg.FromStg a, Stg.Marshal.FromStg.FromStg b) => Stg.Marshal.FromStg.FromStg (a, b) instance (Stg.Marshal.FromStg.FromStg a, Stg.Marshal.FromStg.FromStg b, Stg.Marshal.FromStg.FromStg c) => Stg.Marshal.FromStg.FromStg (a, b, c) instance (Stg.Marshal.FromStg.FromStg a, Stg.Marshal.FromStg.FromStg b, Stg.Marshal.FromStg.FromStg c, Stg.Marshal.FromStg.FromStg d) => Stg.Marshal.FromStg.FromStg (a, b, c, d) instance (Stg.Marshal.FromStg.FromStg a, Stg.Marshal.FromStg.FromStg b, Stg.Marshal.FromStg.FromStg c, Stg.Marshal.FromStg.FromStg d, Stg.Marshal.FromStg.FromStg e) => Stg.Marshal.FromStg.FromStg (a, b, c, d, e) instance Stg.Marshal.FromStg.FromStg a => Stg.Marshal.FromStg.FromStg (GHC.Base.Maybe a) instance (Stg.Marshal.FromStg.FromStg a, Stg.Marshal.FromStg.FromStg b) => Stg.Marshal.FromStg.FromStg (Data.Either.Either a b) instance Stg.Marshal.FromStg.FromStg a => Stg.Marshal.FromStg.FromStg [a] -- | Convert Haskell values to STG values and back. -- -- This module is what users should be using - it reexports only the safe -- classes. module Stg.Marshal -- | Convert a Haskell value to an STG binding. -- -- Instances of this class should have a corresponding FromStg -- instance to retrieve a value fom the program, with the two being -- inverse to each other (up to forcing the generated thunks). -- -- This class contains a helper function, toStgWithGlobals, this -- is hidden from the outside. If you want to write your own instance, -- have a look at the source for documentation. class ToStg value where toStg var val = let (globals, actualDef) = runWriter (toStgWithGlobals var val) in globals <> actualDef toStgWithGlobals var val = pure (toStg var val) toStg :: ToStg value => Var -> value -> Program -- | Look up the value of a global variable. -- -- Instances of this class should have a corresponding ToStg -- instance to inject a value into the program, with the two being -- inverse to each other (up to forcing the generated thunks). class FromStg value where fromStg stgState = globalVal stgState (\case { PrimInt {} -> Left TypeMismatch Addr addr -> fromStgAddr stgState addr }) fromStgPrim _ = Left TypeMismatch -- | Retrieve the value of a global variable. fromStg :: FromStg value => StgState -> Var -> Either FromStgError value -- | Classifies the different errors that can happen when extracting a -- value from an STG state. data FromStgError -- | e.g. asking for an Int# at an address that contains a -- Cons TypeMismatch :: FromStgError -- | Tried retrieving a non-constructor IsWrongLambdaType :: LambdaType -> FromStgError -- | Tried retrieving a black hole IsBlackhole :: FromStgError -- | e.g. Cons x y z BadArity :: FromStgError -- | An unsuccessful variable lookup NotFound :: NotInScope -> FromStgError AddrNotOnHeap :: FromStgError -- | None of the given alternatives matched the given constructor, e.g. -- when trying to receive a Left as a Just NoConstructorMatch :: FromStgError -- | A collection of example programs that might be interesting to look at -- during execution. module Stg.ExamplePrograms -- | A program that calculates x and not y. This is probably the -- simplest example program worth showing. It demonstrates how functions -- are evaluated, has an update for the main closure, and shows -- how nested functions result in let allocations. implies :: Bool -> Bool -> Program -- | A program that adds two numbers. addTwoNumbers :: Integer -> Integer -> Program -- | A program that measures the length of a list. calculateLength :: ToStg a => [a] -> Program -- | Negate a list of booleans, but non-strictly. This program does almost -- nothing, because nothing forces the list. mapNot :: [Bool] -> Program -- | Negate a list of booleans strictly. mapNotForced :: [Bool] -> Program -- | Sum up a list of Integers using -- --
-- sum = foldl' (+) 0 ---- -- This is a good way to sum up a list in Haskell, as it runs in constant -- space. sum_foldl' :: [Integer] -> Program -- | Sum up a list of Integers using -- --
-- sum = foldl' (+) 0 ---- -- where foldl' is implemented via foldr as -- --
-- foldl' f z ys = foldr (x xs acc -> xs $! f acc x) id ys z ---- -- which is a standard "foldl' in terms of foldr" -- definition. This definition is denotationally equivalent to the -- standard foldl', but has a bit more computational overhead. sum_foldl'ViaFoldr :: [Integer] -> Program -- | Sum up a list of Integers using -- --
-- sum = foldl (+) 0 ---- -- This is the canonical space leak in Haskell: note how the accumulator -- is lazy, resulting in a large thunk buildup of suspended additions, -- that is only collapsed to a final value after foldl has -- terminated. The thunks are stored on the heap, so it grows linearly -- with the length of the list. When that thunk is forced, it will push -- lots of additions on the stack; in summary, this produces a heap -- overflow, and if the heap is not exhausted, it will try to overflow -- the stack. sum_foldl :: [Integer] -> Program -- | Sum up a list of Integers using -- --
-- sum = foldr (+) 0 ---- -- Like the foldl version demonstrated in sum_foldl, this -- is a space-leaking implementation of the sum of a list. In this case -- however, the leak spills to the stack and the heap alike: the stack -- contains the continuations for the additions, while the heap contains -- thunks for the recursive call to foldr. sum_foldr :: [Integer] -> Program -- | Calculate the n-th Fibonacci number using the computationally -- (horribly) inefficient formula -- --
-- fib n | n <= 1 = n -- fib n = fib (n-1) + fib (n-2) ---- -- This implementation is stack-only, so enjoy watching it explode. At -- the time of writing this, the machine takes: -- --
-- fib = fib' 0 1 -- where -- fib' x _ | n <= 0 = x -- fib' x !y n = fib' y (x+y) (n-1) ---- -- This implementation is a lot faster than the naive exponential -- implementation. For example, calculating the 10th Fibonacci number -- (55) takes only 490 steps, compared to the many thousands of the -- exponential version. fibonacciImproved :: Integer -> Program -- | Compute the list of Fibonacci numbers eagerly in the contents, but -- lazy in the spine. -- -- This means that the program will successively generate all the -- Fibonacci numbers, allocating new cells of the infinite list and -- calculating their new values, and garbage collecting previous values. -- -- You can picture this as what happens to fibo in the Haskell -- program -- --
-- main = let fibo = zipWith (+) fibo (tail fibo) -- in traverse_ print fibo --fibonacciZipWith :: Program -- | Force a right-associated concatenation -- --
-- [0] ++ ([1] ++ ([2] ++ ([3]))) ---- -- and store it in the main closure. -- -- This computation is linear in the number of elements of the -- sublists. listConcatRightAssociated :: ToStg a => [[a]] -> Program -- | Force a left-associated concatenation -- --
-- (([0] ++ [1]) ++ [2]) ++ [3] ---- -- and store it in the main closure. -- -- This computation is quadratic in the number of elements of the -- sublists. listConcatLeftAssociated :: ToStg a => [[a]] -> Program -- | Sort a list with the canonical Quicksort-inspired algorithm often -- found in introductory texts about Haskell. -- -- Note that this is not Quicksort itself, as one key feature of it is -- sorting in-place. In particular, this algorithm is not all that quick, -- as it takes almost a thousand steps to reach the final state when -- sorting [5,4,3,2,1]. naiveSort :: [Integer] -> Program -- | Sort a list with a translation of Haskell's sort, which is an -- implementation of mergesort with ordered sublist detection. librarySort :: [Integer] -> Program -- | This is a naive implementation of the repeat function, -- --
-- repeat x = x : repeat x ---- -- and it is used to compute the infinite repetition of a number. Run -- this program for a couple hundred steps and observe the heap and the -- garbage collector. Count the GC invocations, and compare it to the -- behaviour of repeatSharing! Also note how long it takes to -- generate two successive list elements. -- -- The reason for this behaviour is that the call to repeat -- x is not shared, but done again for each cons cell, requiring one -- heap allocation every time. Cleaning up after this keeps the GC quite -- busy. repeatNaive :: Program -- | This uses a much better definition of repeat, -- --
-- repeat x = let repeatX = x : repeatX -- in repeatX ---- -- This program does only a total of three heap allocations before -- continuously running without interruption: one for the -- repeated value, one for the self-referencing cons cell, and -- one because of how forceSpine works. -- -- Note how much smaller the cycles between the traversal of two -- neighbouring list cells are! repeatSharing :: Program