-\chapter{Prototype}
- Choice of Haskell
- Core - description of the language (appendix?)
- Stages (-> Core, Normalization, -> VHDL)
- Implementation issues
-
- Haskell language coverage / constraints
- Recursion
- Builtin types
- Custom types (Sum types, product types)
- Function types / higher order expressions
+\chapter[chap:prototype]{Prototype}
+ An important step in this research is the creation of a prototype compiler.
+ Having this prototype allows us to apply the ideas from the previous chapter
+ to actual hardware descriptions and evaluate their usefulness. Having a
+ prototype also helps to find new techniques and test possible
+ interpretations.
+ Obviously the prototype was not created after all research
+ ideas were formed, but its implementation has been interleaved with the
+ research itself. Also, the prototype described here is the final version, it
+ has gone through a number of design iterations which we will not completely
+ describe here.
+
+ \section[sec:prototype:input]{Input language}
+ When implementing this prototype, the first question to ask is: What
+ (functional) language will we use to describe our hardware? (Note that
+ this does not concern the \emph{implementation language} of the compiler,
+ just the language \emph{translated by} the compiler).
+
+ Initially, we have two choices:
+
+ \startitemize
+ \item Create a new functional language from scratch. This has the
+ advantage of having a language that contains exactly those elements that
+ are convenient for describing hardware and can contain special
+ constructs that allows our hardware descriptions to be more powerful or
+ concise.
+ \item Use an existing language and create a new backend for it. This has
+ the advantage that existing tools can be reused, which will speed up
+ development.
+ \stopitemize
+
+ \todo{Sidenote: No EDSL}
+
+ Considering that we required a prototype which should be working quickly,
+ and that implementing parsers, semantic checkers and especially
+ typcheckers is not exactly the core of this research (but it is lots and
+ lots of work!), using an existing language is the obvious choice. This
+ also has the advantage that a large set of language features is available
+ to experiment with and it is easy to find which features apply well and
+ which don't. A possible second prototype could use a custom language with
+ just the useful features (and possibly extra features that are specific to
+ the domain of hardware description as well).
+
+ The second choice is which of the many existing languages to use. As
+ mentioned before, the chosen language is Haskell. This choice has not been the
+ result of a thorough comparison of languages, for the simple reason that
+ the requirements on the language were completely unclear at the start of
+ this research. The fact that Haskell is a language with a broad spectrum
+ of features, that it is commonly used in research projects and that the
+ primary compiler, \GHC, provides a high level API to its internals, made
+ Haskell an obvious choice.
+
+ \note{There should be evaluation of the choice of Haskell and \VHDL}
+
+ \section[sec:prototype:output]{Output format}
+ The second important question is: What will be our output format? Since
+ our prototype won't be able to program FPGA's directly, we'll have to have
+ output our hardware in some format that can be later processed and
+ programmed by other tools.
+
+ Looking at other tools in the industry, the Electronic Design Interchange
+ Format (\small{EDIF}) is commonly used for storing intermediate
+ \emph{netlists} (lists of components and connections between these
+ components) and is commonly the target for \small{VHDL} and Verilog
+ compilers.
+
+ However, \small{EDIF} is not completely tool-independent. It specifies a
+ meta-format, but the hardware components that can be used vary between
+ various tool and hardware vendors, as well as the interpretation of the
+ \small{EDIF} standard. \todo{Is this still true? Reference:
+ http://delivery.acm.org/10.1145/80000/74534/p803-li.pdf?key1=74534\&key2=8370537521\&coll=GUIDE\&dl=GUIDE\&CFID=61207158\&CFTOKEN=61908473}
+
+ This means that when working with \small{EDIF}, our prototype would become
+ technology dependent (\eg only work with \small{FPGA}s of a specific
+ vendor, or even only with specific chips). This limits the applicability
+ of our prototype. Also, the tools we'd like to use for verifying,
+ simulating and draw pretty pictures of our output (like Precision, or
+ QuestaSim) are designed for \small{VHDL} or Verilog input.
+
+ For these reasons, we will not use \small{EDIF}, but \small{VHDL} as our
+ output language. We choose \VHDL over Verilog simply because we are
+ familiar with \small{VHDL} already. The differences between \small{VHDL}
+ and Verilog are on the higher level, while we will be using \small{VHDL}
+ mainly to write low level, netlist-like descriptions anyway.
+
+ An added advantage of using VHDL is that we can profit from existing
+ optimizations in VHDL synthesizers. A lot of optimizations are done on the
+ VHDL level by existing tools. These tools have years of experience in this
+ field, so it would not be reasonable to assume we could achieve a similar
+ amount of optimization in our prototype (nor should it be a goal,
+ considering this is just a prototype).
+
+ Note that we will be using \small{VHDL} as our output language, but will
+ not use its full expressive power. Our output will be limited to using
+ simple, structural descriptions, without any behavioural descriptions
+ (which might not be supported by all tools). This ensures that any tool
+ that works with \VHDL will understand our output (most tools don't support
+ synthesis of more complex \VHDL). This also leaves open the option to
+ switch to \small{EDIF} in the future, with minimal changes to the
+ prototype.
+
+ \section{Prototype design}
+ As suggested above, we will use the Glasgow Haskell Compiler (\small{GHC}) to
+ implement our prototype compiler. To understand the design of the
+ compiler, we will first dive into the \small{GHC} compiler a bit. It's
+ compilation consists of the following steps (slightly simplified):
+
+ \startuseMPgraphic{ghc-pipeline}
+ % Create objects
+ save inp, front, desugar, simpl, back, out;
+ newEmptyBox.inp(0,0);
+ newBox.front(btex Fronted etex);
+ newBox.desugar(btex Desugarer etex);
+ newBox.simpl(btex Simplifier etex);
+ newBox.back(btex Backend etex);
+ newEmptyBox.out(0,0);
+
+ % Space the boxes evenly
+ inp.c - front.c = front.c - desugar.c = desugar.c - simpl.c
+ = simpl.c - back.c = back.c - out.c = (0, 1.5cm);
+ out.c = origin;
+
+ % Draw lines between the boxes. We make these lines "deferred" and give
+ % them a name, so we can use ObjLabel to draw a label beside them.
+ ncline.inp(inp)(front) "name(haskell)";
+ ncline.front(front)(desugar) "name(ast)";
+ ncline.desugar(desugar)(simpl) "name(core)";
+ ncline.simpl(simpl)(back) "name(simplcore)";
+ ncline.back(back)(out) "name(native)";
+ ObjLabel.inp(btex Haskell source etex) "labpathname(haskell)", "labdir(rt)";
+ ObjLabel.front(btex Haskell AST etex) "labpathname(ast)", "labdir(rt)";
+ ObjLabel.desugar(btex Core etex) "labpathname(core)", "labdir(rt)";
+ ObjLabel.simpl(btex Simplified core etex) "labpathname(simplcore)", "labdir(rt)";
+ ObjLabel.back(btex Native code etex) "labpathname(native)", "labdir(rt)";
+
+ % Draw the objects (and deferred labels)
+ drawObj (inp, front, desugar, simpl, back, out);
+ \stopuseMPgraphic
+ \placefigure[right]{GHC compiler pipeline}{\useMPgraphic{ghc-pipeline}}
+
+ \startdesc{Frontend}
+ This step takes the Haskell source files and parses them into an
+ abstract syntax tree (\small{AST}). This \small{AST} can express the
+ complete Haskell language and is thus a very complex one (in contrast
+ with the Core \small{AST}, later on). All identifiers in this
+ \small{AST} are resolved by the renamer and all types are checked by the
+ typechecker.
+ \stopdesc
+ \startdesc{Desugaring}
+ This steps takes the full \small{AST} and translates it to the
+ \emph{Core} language. Core is a very small functional language with lazy
+ semantics, that can still express everything Haskell can express. Its
+ simpleness makes Core very suitable for further simplification and
+ translation. Core is the language we will be working with as well.
+ \stopdesc
+ \startdesc{Simplification}
+ Through a number of simplification steps (such as inlining, common
+ subexpression elimination, etc.) the Core program is simplified to make
+ it faster or easier to process further.
+ \stopdesc
+ \startdesc{Backend}
+ This step takes the simplified Core program and generates an actual
+ runnable program for it. This is a big and complicated step we will not
+ discuss it any further, since it is not required for our prototype.
+ \stopdesc
+
+ In this process, there a number of places where we can start our work.
+ Assuming that we don't want to deal with (or modify) parsing, typechecking
+ and other frontend business and that native code isn't really a useful
+ format anymore, we are left with the choice between the full Haskell
+ \small{AST}, or the smaller (simplified) core representation.
+
+ The advantage of taking the full \small{AST} is that the exact structure
+ of the source program is preserved. We can see exactly what the hardware
+ descriiption looks like and which syntax constructs were used. However,
+ the full \small{AST} is a very complicated datastructure. If we are to
+ handle everything it offers, we will quickly get a big compiler.
+
+ Using the core representation gives us a much more compact datastructure
+ (a core expression only uses 9 constructors). Note that this does not mean
+ that the core representation itself is smaller, on the contrary. Since the
+ core language has less constructs, a lot of things will take a larger
+ expression to express.
+
+ However, the fact that the core language is so much smaller, means it is a
+ lot easier to analyze and translate it into something else. For the same
+ reason, \small{GHC} runs its simplifications and optimizations on the core
+ representation as well.
+
+ However, we will use the normal core representation, not the simplified
+ core. Reasons for this are detailed below. \todo{Ref}
+
+ The final prototype roughly consists of three steps:
+
+ \startuseMPgraphic{clash-pipeline}
+ % Create objects
+ save inp, front, norm, vhdl, out;
+ newEmptyBox.inp(0,0);
+ newBox.front(btex \small{GHC} frontend + desugarer etex);
+ newBox.norm(btex Normalization etex);
+ newBox.vhdl(btex \small{VHDL} generation etex);
+ newEmptyBox.out(0,0);
+
+ % Space the boxes evenly
+ inp.c - front.c = front.c - norm.c = norm.c - vhdl.c
+ = vhdl.c - out.c = (0, 1.5cm);
+ out.c = origin;
+
+ % Draw lines between the boxes. We make these lines "deferred" and give
+ % them a name, so we can use ObjLabel to draw a label beside them.
+ ncline.inp(inp)(front) "name(haskell)";
+ ncline.front(front)(norm) "name(core)";
+ ncline.norm(norm)(vhdl) "name(normal)";
+ ncline.vhdl(vhdl)(out) "name(vhdl)";
+ ObjLabel.inp(btex Haskell source etex) "labpathname(haskell)", "labdir(rt)";
+ ObjLabel.front(btex Core etex) "labpathname(core)", "labdir(rt)";
+ ObjLabel.norm(btex Normalized core etex) "labpathname(normal)", "labdir(rt)";
+ ObjLabel.vhdl(btex \small{VHDL} description etex) "labpathname(vhdl)", "labdir(rt)";
+
+ % Draw the objects (and deferred labels)
+ drawObj (inp, front, norm, vhdl, out);
+ \stopuseMPgraphic
+ \placefigure[right]{Cλash compiler pipeline}{\useMPgraphic{clash-pipeline}}
+
+ \startdesc{Frontend}
+ This is exactly the frontend and desugarer from the \small{GHC}
+ pipeline, that translates Haskell sources to a core representation.
+ \stopdesc
+ \startdesc{Normalization}
+ This is a step that transforms the core representation into a normal
+ form. This normal form is still expressed in the core language, but has
+ to adhere to an extra set of constraints. This normal form is less
+ expressive than the full core language (e.g., it can have limited higher
+ order expressions, has a specific structure, etc.), but is also very
+ close to directly describing hardware.
+ \stopdesc
+ \startdesc{\small{VHDL} generation}
+ The last step takes the normal formed core representation and generates
+ \small{VHDL} for it. Since the normal form has a specific, hardware-like
+ structure, this final step is very straightforward.
+ \stopdesc
+
+ The most interesting step in this process is the normalization step. That
+ is where more complicated functional constructs, which have no direct
+ hardware interpretation, are removed and translated into hardware
+ constructs. This step is described in a lot of detail at
+ \in{chapter}[chap:normalization].
+
+ \section{The Core language}
+ \defreftxt{core}{the Core language}
+ Most of the prototype deals with handling the program in the Core
+ language. In this section we will show what this language looks like and
+ how it works.
+
+ The Core language is a functional language that describes
+ \emph{expressions}. Every identifier used in Core is called a
+ \emph{binder}, since it is bound to a value somewhere. On the highest
+ level, a Core program is a collection of functions, each of which bind a
+ binder (the function name) to an expression (the function value, which has
+ a function type).
+
+ The Core language itself does not prescribe any program structure, only
+ expression structure. In the \small{GHC} compiler, the Haskell module
+ structure is used for the resulting Core code as well. Since this is not
+ so relevant for understanding the Core language or the Normalization
+ process, we'll only look at the Core expression language here.
+
+ Each Core expression consists of one of these possible expressions.
+
+ \startdesc{Variable reference}
+ \defref{variable reference}
+ \startlambda
+ x
+ \stoplambda
+ This is a reference to a binder. It's written down as the
+ name of the binder that is being referred to, which should of course be
+ bound in a containing scope (including top level scope, so a reference
+ to a top level function is also a variable reference). Additionally,
+ constructors from algebraic datatypes also become variable references.
+
+ The value of this expression is the value bound to the given binder.
+
+ Each binder also carries around its type, but this is usually not shown
+ in the Core expressions. Occasionally, the type of an entire expression
+ or function is shown for clarity, but this is only informational. In
+ practice, the type of an expression is easily determined from the
+ structure of the expression and the types of the binders and occasional
+ cast expressions. This minimize the amount of bookkeeping needed to keep
+ the typing consistent.
+ \stopdesc
+
+ \startdesc{Literal}
+ \defref{literal}
+ \startlambda
+ 10
+ \stoplambda
+ This is a literal. Only primitive types are supported, like
+ chars, strings, ints and doubles. The types of these literals are the
+ \quote{primitive} versions, like \lam{Char\#} and \lam{Word\#}, not the
+ normal Haskell versions (but there are builtin conversion functions).
+ \stopdesc
+
+ \startdesc{Application}
+ \defref{application}
+ \startlambda
+ func arg
+ \stoplambda
+ This is function application. Each application consists of two
+ parts: The function part and the argument part. Applications are used
+ for normal function \quote{calls}, but also for applying type
+ abstractions and data constructors.
+
+ The value of an application is the value of the function part, with the
+ first argument binder bound to the argument part.
+ \stopdesc
+
+ \startdesc{Lambda abstraction}
+ \defref{lambda abstraction}
+ \startlambda
+ λbndr.body
+ \stoplambda
+ This is the basic lambda abstraction, as it occurs in labmda calculus.
+ It consists of a binder part and a body part. A lambda abstraction
+ creates a function, that can be applied to an argument. The binder is
+ usually a value binder, but it can also be a \emph{type binder} (or
+ \emph{type variable}). The latter case introduces a new polymorphic
+ variable, which can be used in types later on. See
+ \in{section}[sec:prototype:coretypes] for details.
+
+ Note that the body of a lambda abstraction extends all the way to the
+ end of the expression, or the closing bracket surrounding the lambda. In
+ other words, the lambda abstraction \quote{operator} has the lowest
+ priority of all.
+
+ The value of an application is the value of the body part, with the
+ binder bound to the value the entire lambda abstraction is applied to.
+ \stopdesc
+
+ \startdesc{Non-recursive let expression}
+ \defref{let expression}
+ \startlambda
+ let bndr = value in body
+ \stoplambda
+ A let expression allows you to bind a binder to some value, while
+ evaluating to some other value (where that binder is in scope). This
+ allows for sharing of subexpressions (you can use a binder twice) and
+ explicit \quote{naming} of arbitrary expressions. Note that the binder
+ is not in scope in the value bound to it, so it's not possible to make
+ recursive definitions with the normal form of the let expression (see
+ the recursive form below).
+
+ Even though this let expression is an extension on the basic lambda
+ calculus, it is easily translated to a lambda abstraction. The let
+ expression above would then become:
+
+ \startlambda
+ (λbndr.body) value
+ \stoplambda
+
+ This notion might be useful for verifying certain properties on
+ transformations, since a lot of verification work has been done on
+ lambda calculus already.
+
+ The value of a let expression is the value of the body part, with the
+ binder bound to the value.
+ \stopdesc
+
+ \startdesc{Recursive let expression}
+ \startlambda
+ letrec
+ bndr1 = value1
+ \vdots
+ bndrn = valuen
+ in
+ body
+ \stoplambda
+ This is the recursive version of the let expression. In \small{GHC}'s
+ Core implementation, non-recursive and recursive lets are not so
+ distinct as we present them here, but this provides a clearer overview.
+
+ The main difference with the normal let expression is that each of the
+ binders is in scope in each of the values, in addition to the body. This
+ allows for self-recursive or mutually recursive definitions.
+
+ It should also be possible to express a recursive let using normal
+ lambda calculus, if we use the \emph{least fixed-point operator},
+ \lam{Y}. This falls beyond the scope of this report, since it is not
+ needed for this research.
+ \stopdesc
+
+ \startdesc{Case expression}
+ \defref{case expression}
+ \startlambda
+ case scrutinee of bndr
+ DEFAULT -> defaultbody
+ C0 bndr0,0 ... bndr0,m -> body0
+ \vdots
+ Cn bndrn,0 ... bndrn,m -> bodyn
+ \stoplambda
+
+ \todo{Define WHNF}
+
+ A case expression is the only way in Core to choose between values. All
+ \hs{if} expressions and pattern matchings from the original Haskell
+ PRogram have been translated to case expressions by the desugarer.
+
+ A case expression evaluates its scrutinee, which should have an
+ algebraic datatype, into weak head normal form (\small{WHNF}) and
+ (optionally) binds it to \lam{bndr}. It then chooses a body depending on
+ the constructor of its scrutinee. If none of the constructors match, the
+ \lam{DEFAULT} alternative is chosen. A case expression must always be
+ exhaustive, \ie it must cover all possible constructors that the
+ scrutinee can have (if all of them are covered explicitly, the
+ \lam{DEFAULT} alternative can be left out).
+
+ Since we can only match the top level constructor, there can be no overlap
+ in the alternatives and thus order of alternatives is not relevant (though
+ the \lam{DEFAULT} alternative must appear first for implementation
+ efficiency).
+
+ Any arguments to the constructor in the scrutinee are bound to each of the
+ binders after the constructor and are in scope only in the corresponding
+ body.
+
+ To support strictness, the scrutinee is always evaluated into
+ \small{WHNF}, even when there is only a \lam{DEFAULT} alternative. This
+ allows aplication of the strict function \lam{f} to the argument \lam{a}
+ to be written like:
+
+ \startlambda
+ f (case a of arg DEFAULT -> arg)
+ \stoplambda
+
+ According to the \GHC documentation, this is the only use for the extra
+ binder to which the scrutinee is bound. When not using strictness
+ annotations (which is rather pointless in hardware descriptions),
+ \small{GHC} seems to never generate any code making use of this binder.
+ In fact, \GHC has never been observed to generate code using this
+ binder, even when strictness was involved. Nonetheless, the prototype
+ handles this binder as expected.
+
+ Note that these case statements are less powerful than the full Haskell
+ case statements. In particular, they do not support complex patterns like
+ in Haskell. Only the constructor of an expression can be matched,
+ complex patterns are implemented using multiple nested case expressions.
+
+ Case statements are also used for unpacking of algebraic datatypes, even
+ when there is only a single constructor. For examples, to add the elements
+ of a tuple, the following Core is generated:
+
+ \startlambda
+ sum = λtuple.case tuple of
+ (,) a b -> a + b
+ \stoplambda
+
+ Here, there is only a single alternative (but no \lam{DEFAULT}
+ alternative, since the single alternative is already exhaustive). When
+ it's body is evaluated, the arguments to the tuple constructor \lam{(,)}
+ (\eg, the elements of the tuple) are bound to \lam{a} and \lam{b}.
+ \stopdesc
+
+ \startdesc{Cast expression}
+ \defref{cast expression}
+ \startlambda
+ body :: targettype
+ \stoplambda
+ A cast expression allows you to change the type of an expression to an
+ equivalent type. Note that this is not meant to do any actual work, like
+ conversion of data from one format to another, or force a complete type
+ change. Instead, it is meant to change between different representations
+ of the same type, \eg switch between types that are provably equal (but
+ look different).
+
+ In our hardware descriptions, we typically see casts to change between a
+ Haskell newtype and its contained type, since those are effectively
+ different types (so a cast is needed) with the same representation (but
+ no work is done by the cast).
+
+ More complex are types that are proven to be equal by the typechecker,
+ but look different at first glance. To ensure that, once the typechecker
+ has proven equality, this information sticks around, explicit casts are
+ added. In our notation we only write the target type, but in reality a
+ cast expressions carries around a \emph{coercion}, which can be seen as a
+ proof of equality. \todo{Example}
+
+ The value of a cast is the value of its body, unchanged. The type of this
+ value is equal to the target type, not the type of its body.
+
+ \todo{Move this paragraph}
+ Note that this syntax is also used sometimes to indicate that a particular
+ expression has a particular type, even when no cast expression is
+ involved. This is then purely informational, since the only elements that
+ are explicitely typed in the Core language are the binder references and
+ cast expressions, the types of all other elements are determined at
+ runtime.
+ \stopdesc
+
+ \startdesc{Note}
+ The Core language in \small{GHC} allows adding \emph{notes}, which serve
+ as hints to the inliner or add custom (string) annotations to a core
+ expression. These shouldn't be generated normally, so these are not
+ handled in any way in the prototype.
+ \stopdesc
+
+ \startdesc{Type}
+ \defref{type expression}
+ \startlambda
+ @type
+ \stoplambda
+ It is possibly to use a Core type as a Core expression. For the actual
+ types supported by Core, see \in{section}[sec:prototype:coretypes]. This
+ \quote{lifting} of a type into the value domain is done to allow for
+ type abstractions and applications to be handled as normal lambda
+ abstractions and applications above. This means that a type expression
+ in Core can only ever occur in the argument position of an application,
+ and only if the type of the function that is applied to expects a type
+ as the first argument. This happens for all polymorphic functions, for
+ example, the \lam{fst} function:
+
+ \startlambda
+ fst :: \forall a. \forall b. (a, b) -> a
+ fst = λtup.case tup of (,) a b -> a
+
+ fstint :: (Int, Int) -> Int
+ fstint = λa.λb.fst @Int @Int a b
+ \stoplambda
+
+ The type of \lam{fst} has two universally quantified type variables. When
+ \lam{fst} is applied in \lam{fstint}, it is first applied to two types.
+ (which are substitued for \lam{a} and \lam{b} in the type of \lam{fst}, so
+ the type of \lam{fst} actual type of arguments and result can be found:
+ \lam{fst @Int @Int :: (Int, Int) -> Int}).
+ \stopdesc
+
+ \subsection[sec:prototype:coretypes]{Core type system}
+ Whereas the expression syntax of Core is very simple, its type system is
+ a bit more complicated. It turns out it is harder to \quote{desugar}
+ Haskell's complex type system into something more simple. Most of the
+ type system is thus very similar to that of Haskell.
+
+ We will slightly limit our view on Core's type system, since the more
+ complicated parts of it are only meant to support Haskell's (or rather,
+ \GHC's) type extensions, such as existential types, \small{GADT}s, type
+ families and other non-standard Haskell stuff which we don't (plan to)
+ support.
+
+ In Core, every expression is typed. The translation to Core happens
+ after the typechecker, so types in Core are always correct as well
+ (though you could of course construct invalidly typed expressions).
+
+ Any type in core is one of the following:
+
+ \startdesc{A type variable}
+ \startlambda
+ t
+ \stoplambda
+
+ This is a reference to a type defined elsewhere. This can either be a
+ polymorphic type (like the latter two \lam{t}'s in \lam{id :: \forall t.
+ t -> t}), or a type constructor (like \lam{Bool} in \lam{not :: Bool ->
+ Bool}). Like in Haskell, polymorphic type variables always
+ start with a lowercase letter, while type constructors always start
+ with an uppercase letter.
+
+ \todo{How to define (new) type constructors?}
+
+ A special case of a type constructor is the \emph{function type
+ constructor}, \lam{->}. This is a type constructor taking two arguments
+ (using application below). The function type constructor is commonly
+ written inline, so we write \lam{a -> b} when we really mean \lam{-> a
+ b}, the function type constructor applied to \lam{a} and \lam{b}.
+
+ Polymorphic type variables can only be defined by a lambda
+ abstraction, see the forall type below.
+ \stopdesc
+
+ \startdesc{A type application}
+ \startlambda
+ Maybe Int
+ \stoplambda
+
+ This applies a some type to another type. This is particularly used to
+ apply type variables (type constructors) to their arguments.
+
+ As mentioned above, applications of some type constructors have
+ special notation. In particular, these are applications of the
+ \emph{function type constructor} and \emph{tuple type constructors}:
+ \startlambda
+ foo :: a -> b
+ foo' :: -> a b
+ bar :: (a, b, c)
+ bar' :: (,,) a b c
+ \stoplambda
+ \stopdesc
+
+ \startdesc{The forall type}
+ \startlambda
+ id :: \forall a. a -> a
+ \stoplambda
+ The forall type introduces polymorphism. It is the only way to
+ introduce new type variables, which are completely unconstrained (Any
+ possible type can be assigned to it). Constraints can be added later
+ using predicate types, see below.
+
+ A forall type is always (and only) introduced by a type lambda
+ expression. For example, the Core translation of the
+ id function is:
+ \startlambda
+ id = λa.λx.x
+ \stoplambda
+
+ Here, the type of the binder \lam{x} is \lam{a}, referring to the
+ binder in the topmost lambda.
+
+ When using a value with a forall type, the actual type
+ used must be applied first. For example haskell expression \hs{id
+ True} (the function \hs{id} appleid to the dataconstructor \hs{True})
+ translates to the following Core:
+
+ \startlambda
+ id @Bool True
+ \stoplambda
+
+ Here, id is first applied to the type to work with. Note that the type
+ then changes from \lam{id :: \forall a. a -> a} to \lam{id @Bool ::
+ Bool -> Bool}. Note that the type variable \lam{a} has been
+ substituted with the actual type.
+
+ In Haskell, forall types are usually not explicitly specified (The use
+ of a lowercase type variable implicitly introduces a forall type for
+ that variable). In fact, in standard Haskell there is no way to
+ explicitly specify forall types. Through a language extension, the
+ \hs{forall} keyword is available, but still optional for normal forall
+ types (it is needed for \emph{existentially quantified types}, which
+ Cλash does not support).
+ \stopdesc
+
+ \startdesc{Predicate type}
+ \startlambda
+ show :: \forall a. Show s ⇒ s → String
+ \stoplambda
+
+ \todo{Sidenote: type classes?}
+
+ A predicate type introduces a constraint on a type variable introduced
+ by a forall type (or type lambda). In the example above, the type
+ variable \lam{a} can only contain types that are an \emph{instance} of
+ the \emph{type class} \lam{Show}. \refdef{type class}
+
+ There are other sorts of predicate types, used for the type families
+ extension, which we will not discuss here.
+
+ A predicate type is introduced by a lambda abstraction. Unlike with
+ the forall type, this is a value lambda abstraction, that must be
+ applied to a value. We call this value a \emph{dictionary}.
+
+ Without going into the implementation details, a dictionary can be
+ seen as a lookup table all the methods for a given (single) type class
+ instance. This means that all the dictionaries for the same type class
+ look the same (\eg contain methods with the same names). However,
+ dictionaries for different instances of the same class contain
+ different methods, of course.
+
+ A dictionary is introduced by \small{GHC} whenever it encounters an
+ instance declaration. This dictionary, as well as the binder
+ introduced by a lambda that introduces a dictionary, have the
+ predicate type as their type. These binders are usually named starting
+ with a \lam{$}. Usually the name of the type concerned is not
+ reflected in the name of the dictionary, but the name of the type
+ class is. The Haskell expression \hs{show True} thus becomes:
+
+ \startlambda
+ show @Bool $dShow True
+ \stoplambda
+ \stopdesc
+
+ Using this set of types, all types in basic Haskell can be represented.
+
+ \todo{Overview of polymorphism with more examples (or move examples
+ here)}.
+
+ \section[sec:prototype:statetype]{State annotations in Haskell}
+ \fxnote{This entire section on state annotations should be reviewed}
+
+ Ideal: Type synonyms, since there is no additional code overhead for
+ packing and unpacking. Downside: there is no explicit conversion in Core
+ either, so type synonyms tend to get lost in expressions (they can be
+ preserved in binders, but this makes implementation harder, since that
+ statefulness of a value must be manually tracked).
+
+ Less ideal: Newtype. Requires explicit packing and unpacking of function
+ arguments. If you don't unpack substates, there is no overhead for
+ (un)packing substates. This will result in many nested State constructors
+ in a nested state type. \eg:
+
+ \starttyping
+ State (State Bit, State (State Word, Bit), Word)
+ \stoptyping
+
+ Alternative: Provide different newtypes for input and output state. This
+ makes the code even more explicit, and typechecking can find even more
+ errors. However, this requires defining two type synomyms for each
+ stateful function instead of just one. \eg:
+
+ \starttyping
+ type AccumStateIn = StateIn Bit
+ type AccumStateOut = StateOut Bit
+ \stoptyping
+
+ This also increases the possibility of having different input and output
+ states. Checking for identical input and output state types is also
+ harder, since each element in the state must be unpacked and compared
+ separately.
+
+ Alternative: Provide a type for the entire result type of a stateful
+ function, not just the state part. \eg:
+
+ \starttyping
+ newtype Result state result = Result (state, result)
+ \stoptyping
+
+ This makes it easy to say "Any stateful function must return a
+ \type{Result} type, without having to sort out result from state. However,
+ this either requires a second type for input state (similar to
+ \type{StateIn} / \type{StateOut} above), or requires the compiler to
+ select the right argument for input state by looking at types (which works
+ for complex states, but when that state has the same type as an argument,
+ things get ambiguous) or by selecting a fixed (\eg, the last) argument,
+ which might be limiting.
+
+ \subsubsection{Example}
+ As an example of the used approach, a simple averaging circuit, that lets
+ the accumulation of the inputs be done by a subcomponent.
+
+ \starttyping
+ newtype State s = State s
+
+ type AccumState = State Bit
+ accum :: Word -> AccumState -> (AccumState, Word)
+ accum i (State s) = (State (s + i), s + i)
+
+ type AvgState = (AccumState, Word)
+ avg :: Word -> AvgState -> (AvgState, Word)
+ avg i (State s) = (State s', o)
+ where
+ (accums, count) = s
+ -- Pass our input through the accumulator, which outputs a sum
+ (accums', sum) = accum i accums
+ -- Increment the count (which will be our new state)
+ count' = count + 1
+ -- Compute the average
+ o = sum / count'
+ s' = (accums', count')
+ \stoptyping
+
+ And the normalized, core-like versions:
+
+ \starttyping
+ accum i spacked = res
+ where
+ s = case spacked of (State s) -> s
+ s' = s + i
+ spacked' = State s'
+ o = s + i
+ res = (spacked', o)
+
+ avg i spacked = res
+ where
+ s = case spacked of (State s) -> s
+ accums = case s of (accums, \_) -> accums
+ count = case s of (\_, count) -> count
+ accumres = accum i accums
+ accums' = case accumres of (accums', \_) -> accums'
+ sum = case accumres of (\_, sum) -> sum
+ count' = count + 1
+ o = sum / count'
+ s' = (accums', count')
+ spacked' = State s'
+ res = (spacked', o)
+ \stoptyping
+
+
+
+ As noted above, any component of a function's state that is a substate,
+ \eg passed on as the state of another function, should have no influence
+ on the hardware generated for the calling function. Any state-specific
+ \small{VHDL} for this component can be generated entirely within the called
+ function. So,we can completely leave out substates from any function.
+
+ From this observation, we might think to remove the substates from a
+ function's states alltogether, and leave only the state components which
+ are actual states of the current function. While doing this would not
+ remove any information needed to generate \small{VHDL} from the function, it would
+ cause the function definition to become invalid (since we won't have any
+ substate to pass to the functions anymore). We could solve the syntactic
+ problems by passing \type{undefined} for state variables, but that would
+ still break the code on the semantic level (\ie, the function would no
+ longer be semantically equivalent to the original input).
+
+ To keep the function definition correct until the very end of the process,
+ we will not deal with (sub)states until we get to the \small{VHDL} generation.
+ Here, we are translating from Core to \small{VHDL}, and we can simply not generate
+ \small{VHDL} for substates, effectively removing the substate components
+ alltogether.
+
+ There are a few important points when ignore substates.
+
+ First, we have to have some definition of "substate". Since any state
+ argument or return value that represents state must be of the \type{State}
+ type, we can simply look at its type. However, we must be careful to
+ ignore only {\em substates}, and not a function's own state.
+
+ In the example above, this means we should remove \type{accums'} from
+ \type{s'}, but not throw away \type{s'} entirely. We should, however,
+ remove \type{s'} from the output port of the function, since the state
+ will be handled by a \small{VHDL} procedure within the function.
+
+ When looking at substates, these can appear in two places: As part of an
+ argument and as part of a return value. As noted above, these substates
+ can only be used in very specific ways.
+
+ \desc{State variables can appear as an argument.} When generating \small{VHDL}, we
+ completely ignore the argument and generate no input port for it.
+
+ \desc{State variables can be extracted from other state variables.} When
+ extracting a state variable from another state variable, this always means
+ we're extracting a substate, which we can ignore. So, we simply generate no
+ \small{VHDL} for any extraction operation that has a state variable as a result.
+
+ \desc{State variables can be passed to functions.} When passing a
+ state variable to a function, this always means we're passing a substate
+ to a subcomponent. The entire argument can simply be ingored in the
+ resulting port map.
+
+ \desc{State variables can be returned from functions.} When returning a
+ state variable from a function (probably as a part of an algebraic
+ datatype), this always mean we're returning a substate from a
+ subcomponent. The entire state variable should be ignored in the resulting
+ port map. The type binder of the binder that the function call is bound
+ to should not include the state type either.
+
+ \startdesc{State variables can be inserted into other variables.} When inserting
+ a state variable into another variable (usually by constructing that new
+ variable using its constructor), we can identify two cases:
+
+ \startitemize
+ \item The state is inserted into another state variable. In this case,
+ the inserted state is a substate, and can be safely left out of the
+ constructed variable.
+ \item The state is inserted into a non-state variable. This happens when
+ building up the return value of a function, where you put state and
+ retsult variables together in an algebraic type (usually a tuple). In
+ this case, we should leave the state variable out as well, since we
+ don't want it to be included as an output port.
+ \stopitemize
+
+ So, in both cases, we can simply leave out the state variable from the
+ resulting value. In the latter case, however, we should generate a state
+ proc instead, which assigns the state variable to the input state variable
+ at each clock tick.
+ \stopdesc
+
+ \desc{State variables can appear as (part of) a function result.} When
+ generating \small{VHDL}, we can completely ignore any part of a function result
+ that has a state type. If the entire result is a state type, this will
+ mean the entity will not have an output port. Otherwise, the state
+ elements will be removed from the type of the output port.
+
+
+ Now, we know how to handle each use of a state variable separately. If we
+ look at the whole, we can conclude the following:
+
+ \startitemize
+ \item A state unpack operation should not generate any \small{VHDL}. The binder
+ to which the unpacked state is bound should still be declared, this signal
+ will become the register and will hold the current state.
+ \item A state pack operation should not generate any \small{VHDL}. The binder th
+ which the packed state is bound should not be declared. The binder that is
+ packed is the signal that will hold the new state.
+ \item Any values of a State type should not be translated to \small{VHDL}. In
+ particular, State elements should be removed from tuples (and other
+ datatypes) and arguments with a state type should not generate ports.
+ \item To make the state actually work, a simple \small{VHDL} proc should be
+ generated. This proc updates the state at every clockcycle, by assigning
+ the new state to the current state. This will be recognized by synthesis
+ tools as a register specification.
+ \stopitemize
+
+
+ When applying these rules to the example program (in normal form), we will
+ get the following result. All the parts that don't generate any value are
+ crossed out, leaving some very boring assignments here and there.
+
+
+ \starthaskell
+ avg i --spacked-- = res
+ where
+ s = --case spacked of (State s) -> s--
+ --accums = case s of (accums, \_) -> accums--
+ count = case s of (--\_,-- count) -> count
+ accumres = accum i --accums--
+ --accums' = case accumres of (accums', \_) -> accums'--
+ sum = case accumres of (--\_,-- sum) -> sum
+ count' = count + 1
+ o = sum / count'
+ s' = (--accums',-- count')
+ --spacked' = State s'--
+ res = (--spacked',-- o)
+ \stophaskell
+
+ When we would really leave out the crossed out parts, we get a slightly
+ weird program: There is a variable \type{s} which has no value, and there
+ is a variable \type{s'} that is never used. Together, these two will form
+ the state proc of the function. \type{s} contains the "current" state,
+ \type{s'} is assigned the "next" state. So, at the end of each clock
+ cycle, \type{s'} should be assigned to \type{s}.
+
+ Note that the definition of \type{s'} is not removed, even though one
+ might think it as having a state type. Since the state type has a single
+ argument constructor \type{State}, some type that should be the resulting
+ state should always be explicitly packed with the State constructor,
+ allowing us to remove the packed version, but still generate \small{VHDL} for the
+ unpacked version (of course with any substates removed).
+
+ As you can see, the definition of \type{s'} is still present, since it
+ does not have a state type (The State constructor. The \type{accums'} substate has been removed,
+ leaving us just with the state of \type{avg} itself.
+ \subsection{Initial state}
+ How to specify the initial state? Cannot be done inside a hardware
+ function, since the initial state is its own state argument for the first
+ call (unless you add an explicit, synchronous reset port).
+
+ External init state is natural for simulation.
+
+ External init state works for hardware generation as well.
+
+ Implementation issues: state splitting, linking input to output state,
+ checking usage constraints on state variables.
+
+ \todo{Implementation issues: Separate compilation, simplified core.}
+
+% vim: set sw=2 sts=2 expandtab: