<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Finite Improbability</title>
	<atom:link href="http://blog.finiteimprobability.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.finiteimprobability.com</link>
	<description>Just programming and math, no spontaneously jumping undergarments</description>
	<lastBuildDate>Wed, 10 Mar 2010 17:56:28 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Moving to bitbucket&#8230;</title>
		<link>http://blog.finiteimprobability.com/2010/03/10/moving-to-bitbucket/</link>
		<comments>http://blog.finiteimprobability.com/2010/03/10/moving-to-bitbucket/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 17:56:28 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[compiler]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[raytracing]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=82</guid>
		<description><![CDATA[I&#8217;m moving my projects (yes, all two of them) to bitbucket. You&#8217;ll find them here
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m moving my projects (yes, all two of them) to bitbucket. You&#8217;ll find them <a href="http://bitbucket.org/awj/">here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2010/03/10/moving-to-bitbucket/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lambda Calculus Compiler: Part III: First-Order Functions</title>
		<link>http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/</link>
		<comments>http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 22:18:38 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[compiler]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[llvm]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=75</guid>
		<description><![CDATA[Our last version of this project was a bit … underwhelming. The Lambda Calculus is Turing-equivalent, but it’s hard to imagine expressing much in the way of interesting computations with what we have right now. In fact, we can’t, since our calculator is missing the most important tool of the Lambda Calculus: functions.

In this section, we’ll look at generating first-order functions. It’s easier to understand how functions in LLVM work if we aren’t dealing with the machinery for closures. ]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3>Table of contents for A Lambda Calculus compiler for LLVM</h3><ol><li><a href='http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/' title='A compiler for Lambda Calculus to LLVM, Part 1'>A compiler for Lambda Calculus to LLVM, Part 1</a></li><li><a href='http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/' title='Lambda Calculus compiler, Part II: Wading in with arithmetic'>Lambda Calculus compiler, Part II: Wading in with arithmetic</a></li><li>Lambda Calculus Compiler: Part III: First-Order Functions</li></ol></div> <p>Our last version of this project was a bit &#8230; underwhelming. The
Lambda Calculus is Turing-equivalent, but it&#8217;s hard to imagine
expressing much in the way of interesting computations with what we
have right now. In fact, we can&#8217;t, since our calculator is missing the
most important tool of the Lambda Calculus: functions.</p>

<p>In this section, we&#8217;ll look at generating first-order functions. It&#8217;s
easier to understand how functions in LLVM work if we aren&#8217;t dealing
with the machinery for closures. As always, this post is literate
Haskell. You&#8217;ll need the parser from the first section to compile
it. </p>

<p>Our finished product this time will compile our code into LLVM
bytecode, then disassemble it and print the corresponding LLVM
assembly. It wouldn&#8217;t be much of a stretch to run it as we did last
time, but it also wouldn&#8217;t really explain much either. We&#8217;re still at
a point where reading the generated assembly can convince us of
correct results.</p>

<pre><code>&gt; module Main where

&gt; import Parser
</code></pre>

<p>As before, we&#8217;re going to need a bunch of imports.</p>

<pre><code>&gt; import Control.Monad.State(forever)
&gt; import Data.Int
&gt; import Data.List
&gt; import LLVM.Core
&gt; import LLVM.Util.File(writeCodeGenModule)

&gt; import System.IO
&gt; import System.Cmd
</code></pre>

<p>Our environment from the calculator needs to be extended to keep track
of functions. In theory we could look up and store the name of newly
generated functions here, but it&#8217;s easier to store the functions
directly.</p>

<pre><code>&gt; data Env = Env {
&gt;       vars :: [(String, Value Int32)]
&gt;     , funs :: [(String, Function (Int32 -&gt; IO Int32))]
&gt;     }
</code></pre>

<p>It&#8217;s nice to be able to print the variables we already have, so we&#8217;ll
make <code>Env</code> an instance of <code>Show</code> to help with that.</p>

<pre><code>&gt; instance Show Env where
&gt;     show e = "vars: " ++ (m $ vars e) ++ ", " ++
&gt;              "funs: " ++ (m $ funs e) where
&gt;                   m l = show $ names l
</code></pre>

<p>At several times we&#8217;ll need to separate the names from the values in
our environment. In fact we&#8217;ve already needed to once.</p>

<pre><code>&gt; names = map fst
</code></pre>

<p>Here&#8217;s our familiar AST -> LLVM translation of arithmetic operations.</p>

<pre><code>&gt; getOpt Add = add
&gt; getOpt Mul = mul
</code></pre>

<h1>Detecting Closures</h1>

<p>Since we&#8217;re restricting ourselves to first-order functions, we need to
take some steps to detect (and fail on) higher-order functions. In
some ways we can continue to be bad compiler writers and rely on the
user to follow arcane and senseless rules. This is exactly the
technique I will be using to prevent functions as arguments and
functions as return values.</p>

<p>However, there&#8217;s one other feature we need to prevent, and that&#8217;s
closures. Obviously we could expect the user to avoid those as well,
but in this case the code we need to detect them now will be
convenient later. Since this project is all about doing things that
are convenient for us as the compiler writers (enjoy it now, this
almost never happens in real life), we&#8217;ll go ahead and implement that
check.</p>

<p>So, what does a closure look like in an abstract syntax tree? The
answer is pretty simple: a closures references variables from its
surrounding environment, so build up a list of all the name references
in a piece of the AST and eliminate the ones that are declared in that
piece. What is left is the variables that are being closed over.</p>

<p>Here&#8217;s an example of a perfectly valid first-order function, the
identity function:</p>

<pre><code>\x. x
</code></pre>

<p>There&#8217;s only one variable involved, <code>x</code>, and we can easily see that it
is introduced in the lambda terms, so the identity function has no
free variables.</p>

<p>In this example, the function bound to g is a closure:</p>

<pre><code>let f = 5; g = \x. x + f in g 2
</code></pre>

<p>That&#8217;s easy to see when we pull it out of its context:</p>

<pre><code>\x. x + f
</code></pre>

<p>We can still identify where <code>x</code> &#8220;comes from&#8221;, but now there&#8217;s nothing
to provide the definition of <code>f</code>. In this situation <code>f</code> is called a
<em>free variable</em>, and it&#8217;s the presence of these that differentiates
closures from more ordinary functions.</p>

<p>Now that we have a handle on what free variables are, on to detecting
them. We&#8217;ll need a function that takes an expression and generates a
list of the free variables in it.</p>

<pre><code>&gt; fv              :: Exp -&gt; [Var]
</code></pre>

<p>Perhaps the simplest way to structure this is to go through each
constructor for our AST and decide how to find free variables for that
constructor. Vars are simple, since they&#8217;re just a variable name with
nothing to bind them to a value, they&#8217;re automatically free variables.</p>

<pre><code>&gt; fv (EVar v)      = [v]
</code></pre>

<p>Constants have no variables, so there&#8217;s no free variables to be found
here.</p>

<pre><code>&gt; fv (Con _)       = []
</code></pre>

<p>Function applications have two places they could contain free
variables. The obvious one is the expression the function is being
applied to, but the slightly-less-obvious case inovlves the function
itself. Remember, we eventually will have functions that can return
functions, so something like <code>(f 2) 2</code> will eventually be valid, and
leaves plenty of room to start closing over variables.</p>

<p>This isn&#8217;t tough to account for though, just have to look up the free
variables in both, then filter the list to eliminate
duplicates. Luckily, <code>nub</code> from <code>Data.List</code> has already been written
to take care of just this issue.</p>

<pre><code>&gt; fv (App f x)     = nub (fv f ++ fv x)
</code></pre>

<p>Lambda terms are one of our two constructs that are capable of binding
a name. We need to make sure we don&#8217;t accidentally declare the
function argument as a free variable, since we know exactly what it&#8217;s
value is. The function <code>(\\)</code> scans a list on the left to remove any
items from the list on the right, so we can just look up the free
variables in our lambda terms expression then pluck out the one that
doesn&#8217;t belong.</p>

<pre><code>&gt; fv (Lam v e)     = fv e \\ [v]
</code></pre>

<p>Arithmetic operations can close over variables in their left or right
terms. Again, we should clean up the list so any given free variable
is only present once.</p>

<pre><code>&gt; fv (EOp _ l r)   = nub (fv l ++ fv r)
</code></pre>

<p>Let bindings are our other construct that can bind a name. The steps
needed here are about the same as those for lambda expressions.</p>

<pre><code>&gt; fv (Let v eq xp) = nub $ fv eq ++ ([v] \\ fv xp)
</code></pre>

<h1>Generating Functions</h1>

<p>Now that we can identify free variables, we&#8217;re pretty much ready to
start compiling functions. This has to happen within the
<code>CodeGenModule</code> monad, which is fine now but will complicate our
closure code a bit in the next section. We&#8217;ll rewrite <code>compileFun</code>
from the calculator to support the kinds of functions we&#8217;re
defining. We&#8217;ll have to change the type signature to match the <code>Int -&gt;
Int</code> functions our lambda calculus uses.</p>

<p>While creating a function, we&#8217;re inside of the <code>CodeGenFunction</code>
monad, and thus can compile its body using the code from our
calculator (remember, we&#8217;re trusting the users not to write any
&#8220;interesting&#8221; functions).</p>

<p>The only tricky part left is distinguishing closures from
non-closures, but that&#8217;s pretty simple, just look up the free
variables of the function. If there are any we have a closure and
throw an error, otherwise we can compile it.</p>

<p>The only interesting aspect of compiling the body of our function is
that we have to add the argument to our environment while compiling
the body. Since the code for this looks kind of ugly, we&#8217;ll wrap it in
a slightly prettier function.</p>

<pre><code>&gt; addv :: Var -&gt; Value Int32 -&gt; Env -&gt; Env
&gt; addv v x e = e {vars = ((v::String),x):vars e}
</code></pre>

<p>Finally, we&#8217;re ready to compile functions. Since the only piece of our
AST that can product a function is a lambda term, that&#8217;s the only
piece we can meaningfully compile.</p>

<pre><code>&gt; compileFun :: Env -&gt; Exp -&gt; CodeGenModule (Function (Int32 -&gt; IO Int32))
&gt; compileFun env f@(Lam v e) = case (fv f) of
&gt;                                []        -&gt;  createFunction ExternalLinkage $ \x -&gt; do
&gt;                                                        t &lt;- compileExp (addv v x env) e
&gt;                                                        ret t
&gt;                                otherwise -&gt; error "No closures yet!"
&gt; compileFun _ _ = error "undefined"
</code></pre>

<p>Due to the restrictions we have in place, we&#8217;ll expect to see a set of
nested lets that introduce functions, and a final body that uses
them. We can special case the compilation of this to ensure our
eventual body is in a special function.</p>

<p>First, we&#8217;ll need a convenience function to introduce a function to
the environment. This is almost the same as <code>addv</code>, with an obvious
change to the record being updated.</p>

<pre><code>&gt; addf :: Var -&gt; (Function (Int32 -&gt; IO Int32)) -&gt; Env -&gt; Env
&gt; addf f x e = e {funs = ((f::String),x):funs e}
</code></pre>

<p>When compiling lets, we&#8217;re going to start out only dealing with lets
that bind a lambda term to a name. The process is relatively simple:
compile the function, store it in the environment under the name it
was bound do, and compile the let body with that environment.</p>

<pre><code>&gt; compileLet :: Env -&gt; Exp -&gt; CodeGenModule Env
&gt; compileLet env l@(Let v fun@(Lam x exp) body) =
&gt;                         do fn &lt;- compileFun env fun
&gt;                            letBody v (addf v fn env) body
&gt; compileLet _ _ = error "undefined"
</code></pre>

<p>While we&#8217;re compiling the let body, we need so way to decide where to
&#8220;stop&#8221; and emit our final function. We can pile on one more
restriction to help with this: let bindings that introduce functions
must come before those that bind non-function values. That way once we
see a let which <em>doesn&#8217;t</em> introduce a function, we can emit our main
function and compile as normal in that.</p>

<p>Note that we don&#8217;t really need this restriction. Since functions
aren&#8217;t being allowed to close over their environment, we could pull
all of the non-function bindings past the function bindings without
changing the meaning of the program. That would be a good exercise to
try.</p>

<p>To decide when to stop making more functions, we need to distinguish
lets that bind a function from those that bind a value. It doesn&#8217;t get
much simpler than this:</p>

<pre><code>&gt; isFunLet :: Exp -&gt; Bool
&gt; isFunLet (Let _ (Lam _ _) _) = True
&gt; isFunLet _                   = False
</code></pre>

<p>The body of each let can meet one of two criteria. It either contains
another let that defines a function, in which case we need to keep
compiling functions, or it doesn&#8217;t, in which case we&#8217;ve hit the &#8220;body&#8221;
of our main function and can compile that. For convenience we&#8217;re
adding an unused parameter to the main function so its type matches
that of the others and we can return it with the entire environment.</p>

<pre><code>&gt; letBody :: Var -&gt; Env -&gt; Exp -&gt; CodeGenModule Env
&gt; letBody v env expr | isFunLet expr = do compileLet env expr
&gt;                    | otherwise     =
&gt;                        do f &lt;- createNamedFunction ExternalLinkage "main" $ \n -&gt;
&gt;                                                      do t &lt;- compileExp env expr; ret t
&gt;                           return $ addf v f env
&gt;                                                                     
</code></pre>

<h1>Compilation, extended</h1>

<p>Since we now have functions <em>and</em> variables, let&#8217;s add a bit more
useful error handling to make life simpler.</p>

<pre><code>&gt; envError :: String -&gt; String -&gt; Env -&gt; a
&gt; envError "function" n e = error $ "could not find function: " ++ n ++ ", have: " ++ (show $ names $ funs e)
&gt; envError "variable" n e = error $ "could not find variable: " ++ n ++ ", have: " ++ (show $ names $ vars e)
&gt; envError t _ _ = error $ "unrecognized error type: " ++ t
</code></pre>

<p>The code to compile expressions is largely unchanged, with the
exception that we&#8217;re now supporting function application.</p>

<pre><code>&gt; compileExp :: Env -&gt; Exp -&gt; CodeGenFunction r (Value Int32)
&gt; compileExp _ (Con x)       = return $ valueOf ((fromIntegral x)::Int32)

&gt; compileExp e (EOp o l r)   = do
&gt;                              l' &lt;- compileExp e l
&gt;                              r' &lt;- compileExp e r
&gt;                              getOpt o l' r'

&gt; compileExp e (EVar v)      = case lookup v $ vars e of
&gt;                             Just a  -&gt; return a
&gt;                             Nothing -&gt; envError "variable" v e

&gt; compileExp env@(Env e f) (Let v val body) = do
&gt;                  v' &lt;- compileExp env val
&gt;                  let e' = Env (((v::String),v'):e) f in
&gt;                           compileExp e' body
</code></pre>

<p>Due to the restrictions we have in place, we don&#8217;t have to worry about
expressions that result in a function. Our code just has to handle
variables bound to a give function. It does this by looking up the
function in our environment (obviously failing if it isn&#8217;t found),
then compiling the argument into a register and calling the function
with that register as its argument.</p>

<pre><code>&gt; compileExp e (App (EVar v) e2)  = case lookup v $ funs e of
&gt;                                     Just a -&gt; do
&gt;                                       t1 &lt;- compileExp e e2
&gt;                                       call a t1
&gt;                                     Nothing -&gt; envError "function" v e
&gt; compileExp _ _            = error "undefined"
</code></pre>

<p>To start off our compilation, we&#8217;ll need an empty environment. Here it
is.</p>

<pre><code>&gt; emptyEnv = Env [] []
</code></pre>

<p>Our main function is unchanged from last time.</p>

<pre><code>&gt; main =
&gt;     forever $ 
&gt;     do putStr "&gt; "
&gt;        hFlush stdout -- have to flush for proper output ordering
&gt;        s &lt;- getLine
&gt;        go s
</code></pre>

<p>Now, <code>go</code> has been rewritten to compile our code into llvm bytecode,
use a shell command to disassemble it, then read the disassembled
output and print it to the screen.</p>

<pre><code>&gt; go s =
&gt;   case runwith letexpr id s of
&gt;   Left err  -&gt; putStrLn $ show err
&gt;   Right exp -&gt; do writeCodeGenModule "FirstClass.bc" $ compileLet emptyEnv exp
&gt;                   rawSystem "llvm-dis" ["-f", "FirstClass.bc"]
&gt;                   f &lt;- readFile "FirstClass.ll"
&gt;                   putStr f
</code></pre>
 <div class='series_links'><a href='http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/' title='Lambda Calculus compiler, Part II: Wading in with arithmetic'>Previous in series</a> </div>]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Lambda Calculus compiler, Part II: Wading in with arithmetic</title>
		<link>http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/</link>
		<comments>http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 00:13:02 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[compiler]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[llvm]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=70</guid>
		<description><![CDATA[Rather than dive entirely into working on a compiler, I&#8217;m going to
approach the task in pieces. This post will go over how the Haskell
LLVM bindings work while creating support for computing algebraic
expressions. The next post will cover first-order functions, with
closures to follow.

This calculator will be a standalone program that takes in algebraic
equations on the command [...]]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3>Table of contents for A Lambda Calculus compiler for LLVM</h3><ol><li><a href='http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/' title='A compiler for Lambda Calculus to LLVM, Part 1'>A compiler for Lambda Calculus to LLVM, Part 1</a></li><li>Lambda Calculus compiler, Part II: Wading in with arithmetic</li><li><a href='http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/' title='Lambda Calculus Compiler: Part III: First-Order Functions'>Lambda Calculus Compiler: Part III: First-Order Functions</a></li></ol></div> <p>Rather than dive entirely into working on a compiler, I&#8217;m going to
approach the task in pieces. This post will go over how the Haskell
LLVM bindings work while creating support for computing algebraic
expressions. The next post will cover first-order functions, with
closures to follow.</p>

<p>This calculator will be a standalone program that takes in algebraic
equations on the command line, compiles them into LLVM bytecode, runs
that code and prints the result. At the time of this writing, the LLVM
bindings cannot load functions generated at runtime in ghci, so if
you&#8217;re following along you&#8217;ll have to statically compile the result.</p>

<p>As before, this post is literate Haskell. It needs the LLVM bindings
installed and set up correctly, and uses the parser from the last
post. Please note that I needed to make a couple of changes to the
parser module, so if you downloaded a copy before this post existed,
you should grab an update.</p>

<pre><code>&gt; module Main where

&gt; import Parser

&gt; import Control.Monad.State
&gt; import Control.Monad(join)

&gt; import Data.Int

&gt; import LLVM.Core
&gt; import LLVM.ExecutionEngine
&gt; import LLVM.Util.Arithmetic
&gt; import LLVM.Util.File(writeCodeGenModule)

&gt; import System.IO
</code></pre>

<p>The Haskell LLVM bindings can be split into two levels. There&#8217;s a low
level interface that doesn&#8217;t give much more than direct bindings to
the C++ api. This is great as a fallback, but can be rather tedious to
work with.</p>

<p>The high level api provides translation between Haskell and LLVM
values, and heavy-duty abstractions for generating LLVM bytecode. Most
of this abstraction is provided by a CodeGen monad, which keeps track
of basic blocks and uses the syntactic sugar of do blocks to make your
code look significantly like assembly psuedocode.</p>

<h1>Simplifying Assumptions</h1>

<p>In order to get very far in compiling arithmetic expressions in a
reasonable amount of time, we&#8217;ll need to make a few simplifying
assumptions. Some are obvious, like that we won&#8217;t be dealing with
functions at this point and can unhelpfully error out when someone
tries to use one. Others are slightly more subtle.</p>

<p>In reality, after we&#8217;ve parsed the input, we should really be doing
some checks on the output to ensure it is valid. This includes things
like ensuring someone doesn&#8217;t try to add together a number and a
lambda expression. If you look back at the parser, you&#8217;ll notice it
was carefully structured to avoid this specific problem.</p>

<p>An issue we <em>aren&#8217;t</em> going to deal with is name conflicts. A real
compiler would add an identifier renaming pass that ensures all name
references are unique. Since this is a budget compiler, we&#8217;re going to
assume the program was careful and did that for us. It isn&#8217;t exactly
hard to do this, just a bit tedious, and might be worth experimenting
with as an exercise.</p>

<p>It also makes life a lot easier if we require that names be defined
before they are used. Haskell allows code like this:</p>

<pre><code>let f = g + 5
    g = 10 in
    ...
</code></pre>

<p>In order to compile <code>f</code>, we need to know what <code>g</code> is. The obvious
answer is to come up with a way to wait on compiling <code>f</code> until we&#8217;ve
either compiled <code>g</code> or compiled everything there is to compile and not
seen <code>g</code>, but that is a lot of work. This also might be something
worth doing for practice though.</p>

<p>Another simplifying assumption that we&#8217;re making is assuming our
programmers are only interested in creating functions that add or
multiply 32-bit integer values. Partly this is done to avoid work,
like supporting floating point values, that I feel isn&#8217;t quite
interesting enough to be worth the effort for this kind of toy
project. The 32-bit part is just plain cheating so we can easily
convert from a Haskell Int32 to an LLVM integer on any kind of system.</p>

<h1>Compilation Miscellany</h1>

<p>In order to compile our programs, we need an environment that tracks
the register a value was compiled into. This can be done with a simple
association list of identifier names to register values, which the
prelude handily defines a few functions to work with.</p>

<p>The type: <code>Value Int32</code> corresponds to an llvm register storing a
32-bit integer. This environment would obviously need some adjusting
if we wanted to support other kinds of values. The LLVM bindings
approach this through limiting <code>Value a</code> based on appropriate type
classes and the existential types extension. That would probably be
the best bet to proceed from here.</p>

<pre><code>&gt; type Env = [(String, Value Int32)]
</code></pre>

<p>The LLVM bindings provide <code>add</code> and <code>mul</code> instructions that take two
registers (or immediate values) and produce the appropriate
result. We&#8217;ll need a function to translate the operations from our AST
into the equivalent LLVM functions.</p>

<pre><code>&gt; getOpt Add = add
&gt; getOpt Mul = mul
</code></pre>

<h1>Compiling Expressions</h1>

<p>Our entire compilation step can be expressed with a single
function. Since we will want to reference variables bound in a
containing let, that function will obviously need to accept the
environment as an argument. The function will walk the AST, compiling
results as it goes and trusting the CodeGen monad to do all of the
bookkeeping.</p>

<p>The result of our expression compilation will be a register, bound up
in the CodeGen monad. This is about the area where my understanding of
Haskell gets fuzzy, so I can&#8217;t fully explain the reasoning behind the
return value of this function.</p>

<pre><code>&gt; compileExp :: Env -&gt; Exp -&gt; CodeGenFunction r (Value Int32)
</code></pre>

<p>Compiling a constant is simple, just convert the AST&#8217;s string (we
already know it&#8217;s an integer, thanks to the parser) to a Haskell
Int32, then pass that to <code>valueOf</code> for conversion to an LLVM Int32,
and bind the whole thing up in our monad.</p>

<pre><code>&gt; compileExp _ (Con x)       = return $ valueOf ((fromIntegral x)::Int32)
</code></pre>

<p>Likewise, compiling a variable is as simple as looking up the register
it was previously compiled into based on the variable name. Since
we&#8217;re not trying to be useful compiler writers, we&#8217;ll just give an
error and exit if we can&#8217;t find the variable name.</p>

<pre><code>&gt; compileExp e (EVar v)      = case lookup v e of
&gt;                             Just e  -&gt; return e
&gt;                             Nothing -&gt; error $ "could not find variable: " ++ v
</code></pre>

<p>Compiling an arithmetic expression is a simple matter of compiling
each side, then performing the arithmetic on the result.</p>

<pre><code>&gt; compileExp e (EOp o l r)   = do
&gt;                              l' &lt;- compileExp e l
&gt;                              r' &lt;- compileExp e r
&gt;                              (getOpt o) l' r'
</code></pre>

<p>Let bindings are the only way to introduce variable names into the
environment. The body of the let needs the variable to be bound to the
value. For now we&#8217;re going to assume the value is not a lambda
expression, in which case we can simply compute it into a register and
associate that register with the variable name when compiling the body
of the let.</p>

<pre><code>&gt; compileExp e (Let v val body) = do
&gt;                  v' &lt;- compileExp e val
&gt;                  let e' = ((v::String),v'):e in
&gt;                           compileExp e' body
</code></pre>

<p>Just to be clear, we&#8217;ll make sure that everything else (function
application and lambda expressions) gives an error.</p>

<pre><code>&gt; compileExp _ _            = error "none of that, I'm still cheating"
</code></pre>

<p>Our &#8220;calculator&#8221; portion is formed by wrapping the expression in an
LLVM function that computes it and returns the result. Here&#8217;s a simple
function that does just that.</p>

<p>Since this is the first time we&#8217;ve actually made a function, it
warrants going over what&#8217;s happening here. The <code>createFunction</code>
function does pretty much what you would expect. It needs an argument
detailing the link-time visibility of the function. For our specific
purposes the parameter is irrelevant, but it&#8217;s there if you need it.</p>

<p>Notice that we aren&#8217;t providing a <em>name</em> for the function. Even
according to our bindings we&#8217;re still working with anonymous
functions! Of course, if you decompile the resulting bytecode you&#8217;ll
see that LLVM comes up with names like <code>@_fun1</code>.</p>

<p>Our function takes no arguments, and simply compiles the expression,
stores the result into a register, and returns it. Couldn&#8217;t be easier
than that. The <code>Function</code> type represents this. If our function had
taken a single integer argument its type would look like <code>Function
(Int32 -&gt; IO Int32)</code>. Since we&#8217;re calling out to bindings that do all
kinds of IO work, it&#8217;s reasonable to expect the IO monad to show
up. With this type of declaration it&#8217;s impossible to call the function
we&#8217;re making without being in the IO monad or committing irredeemable
sins. We&#8217;ll try to keep our functional hearts pure, at least for the
rest of this module.</p>

<pre><code>&gt; compileFun :: Exp -&gt; CodeGenModule (Function (IO Int32))
&gt; compileFun exp = createFunction ExternalLinkage $ do
&gt;                    t &lt;- compileExp [] exp
&gt;                    ret t
</code></pre>

<p>Now we can wrap up the process of compiling our function and binding
to it in Haskell. The LLVM bindings provide <code>simpleFunction</code> for just
this task.</p>

<pre><code>&gt; compileToFun :: Exp -&gt; IO Int32
&gt; compileToFun exp = join $ simpleFunction $ compileFun exp
</code></pre>

<p>Our main function will simply loop forever, pulling in user input and
running it through something to respond to it.</p>

<pre><code>&gt; main =
&gt;     forever $ 
&gt;     do putStr "&gt; "
&gt;        hFlush stdout -- have to flush for proper output ordering
&gt;        s &lt;- getLine
&gt;        go s
</code></pre>

<p>Here&#8217;s the heart of our calculator. It attempts to parse the user&#8217;s
input (generating an error message on failure), then compiles it and
runs the containing function to get the result. Finally it writes the
bytecode out to <code>Calc.bc</code>.</p>

<pre><code>&gt; go s =
&gt;   case runwith letexpr id s of
&gt;   Left err  -&gt; putStrLn $ show err
&gt;   Right exp -&gt; do let fun = compileToFun exp in
&gt;                             do r &lt;- fun
&gt;                                putStrLn $ "result: " ++ (show r)
&gt;                                writeCodeGenModule "Calc.bc" $ compileFun exp
&gt;                                                          
</code></pre>

<p>This file can be disassembled with <code>llvm-dis</code>, which generates
somewhat surprising output. No matter how complicated your let
bindings or arithmetic expression, you&#8217;ll always get a function that
simply returns the pre-computed result. LLVM has an extensive number
of optimization passes, and a good selection of them are enabled for
you by default in the Haskell bindings. One of these is the <em>constant
propogation</em> pass, which looks for arithmetic that can be done at
compile time and eliminates the intermediary computation.</p>

<p>I&#8217;ll walk through an example, to show how the magic works. We&#8217;ll start
with this expression:</p>

<pre><code>let f = 5; g = 2 in 4 * f + (20 + 2)
</code></pre>

<p>It parses into:</p>

<pre><code>Let "f" (Con 5)
  (Let "g" (Con 2)
    (EOp Add
      (EOp Mul (Con 4) (EVar "f"))
      (EOp Add (Con 20) (Con 2))))
</code></pre>

<p>A (very) naive &#8220;hand-compilation&#8221; would give us something like the
following:</p>

<pre><code>define internal i32 @_fun1() {
_L1:
        %1 = $5
        %2 = $2
        %3 = mul $4 %1
        %4 = add $20 %2
        %5 = add %3 %4
        ret i32 %5
}
</code></pre>

<p>First off, we obviously don&#8217;t need the %1 and %2 registers, all they
do is hold constants. It&#8217;s simple to push their values into the
relevant expressions. This act of recognizing a constant and using it
to replace the register it was being stored in is <em>constant
propagation</em>. Once that push has happened, the %1 and %2 registers
become unused, and can be dropped.</p>

<pre><code>define internal i32 @_fun1() {
_L1:
        %3 = mul $4 $5
        %4 = add $20 $2
        %5 = add %3 %4
        ret i32 %5
}
</code></pre>

<p>Now we can look at the %3 register, which just multiplies two
constants. We know how to do that too, and it&#8217;s no stretch to handle
the addition on %4. This optimization, called <em>constant folding</em>, is
closely related to constant propagation.</p>

<pre><code>define internal i32 @_fun1() {
_L1:
        %3 = $20
        %4 = $22
        %5 = add %3 %4
        ret i32 %5
}
</code></pre>

<p>But now we&#8217;ve got more registers that are nothing but labels for
constants, you know what to do.</p>

<pre><code>define internal i32 @_fun1() {
_L1:
        %5 = add $20 $22
        ret i32 %5
}
</code></pre>

<p>Now we&#8217;re another constant fold &amp; propagate step away from the exact
output LLVM gives us, which is:</p>

<pre><code>define internal i32 @_fun1() {
_L1:
        ret i32 $42
}
</code></pre>

<p>Tune in next time for first-order functions.</p>
 <div class='series_links'><a href='http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/' title='A compiler for Lambda Calculus to LLVM, Part 1'>Previous in series</a> <a href='http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/' title='Lambda Calculus Compiler: Part III: First-Order Functions'>Next in series</a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A compiler for Lambda Calculus to LLVM, Part 1</title>
		<link>http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/</link>
		<comments>http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 01:52:36 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[compiler]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[llvm]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=52</guid>
		<description><![CDATA[In this series of posts, I&#8217;m going to walk through building a compiler
for a simple Lambda Calculus to llvm. I&#8217;ll try to keep things to the
point that nothing more than a general understanding of Haskell,
Parsec, and the basic concepts of LLVM are required.

If you&#8217;d like to follow along, this post is a Literate Haskell
file. That [...]]]></description>
			<content:encoded><![CDATA[<div class='series_toc'><h3>Table of contents for A Lambda Calculus compiler for LLVM</h3><ol><li>A compiler for Lambda Calculus to LLVM, Part 1</li><li><a href='http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/' title='Lambda Calculus compiler, Part II: Wading in with arithmetic'>Lambda Calculus compiler, Part II: Wading in with arithmetic</a></li><li><a href='http://blog.finiteimprobability.com/2009/12/03/lambda-calculus-compiler-part-iii-first-order-functions/' title='Lambda Calculus Compiler: Part III: First-Order Functions'>Lambda Calculus Compiler: Part III: First-Order Functions</a></li></ol></div> <p>In this series of posts, I&#8217;m going to walk through building a compiler
for a simple <a href="http://en.wikipedia.org/wiki/Lambda_calculus">Lambda Calculus</a> to <a href="http://llvm.org">llvm</a>. I&#8217;ll try to keep things to the
point that nothing more than a general understanding of Haskell,
<a href="http://www.haskell.org/haskellwiki/Parsec">Parsec</a>, and the basic concepts of LLVM are required.</p>

<p>If you&#8217;d like to follow along, this post is a Literate Haskell
file. That is unless Wordpress broke it, in which case let me know and
I&#8217;ll fix it.</p>

<p>This first post concentrates on the parser. We&#8217;re going to target the
abstract syntax found below. It&#8217;s a relatively simple untyped Lambda
Calculus, with the conceit of adding let bindings to make life a bit
more interesting. Note that we&#8217;re simplifying things considerably by
limiting our types and arithmetic operations to stay within the realm
of positive integers.</p>

<p>For educational value, I <em>will not</em> be using
<code>Text.ParserCombinators.Parsec.Language</code>. Please note that, if you&#8217;re
trying to implement a &#8220;real&#8221; language parser, that&#8217;s a much more sane
option.</p>

<p>Let&#8217;s get started. We&#8217;re going to need to define a module for htis,
and we obviously need some parsec libraries as well as the AST we&#8217;re
translating to, so let&#8217;s take care of that.</p>

<pre><code>&gt; module Parser(letexpr, runwith, runIO,
&gt;               Exp(EVar, Let, App, Lam, EOp, Con),
&gt;               Op(Add, Mul),
&gt;               Var) where

&gt; import Data.List

&gt; import Text.ParserCombinators.Parsec
&gt; import Text.ParserCombinators.Parsec.Error(messageString, errorMessages)
</code></pre>

<p>Here&#8217;s the AST I will be using:</p>

<pre><code>&gt; data Exp  = EVar Var
&gt;           | Let Var Exp Exp
&gt;           | App Exp Exp
&gt;           | Lam Var Exp
&gt;           | EOp Op Exp Exp
&gt;           | Con Int
&gt;             deriving Show

&gt; type Var  = String

&gt; data Op = Add
&gt;         | Mul
&gt;           deriving Show
</code></pre>

<p>I&#8217;m going to start out by defining a few useful tools. It&#8217;s entirely
likely that these already exist in Parsec, and furthermore that my
implementations are inferior, so please let me know if you spot a
problem.</p>

<p>Expressing &#8220;this should be between spaces&#8221; is a pain, so we&#8217;ll make
something to handle that. But, we don&#8217;t want &#8220;expected space or&#8230;&#8221; in
all of our errors, so this isn&#8217;t as intuitive as it would seem:</p>

<pre><code>&gt; spaced x = between spaces' spaces' x where
&gt;     spaces' = spaces &lt;?&gt; ""
</code></pre>

<p>We&#8217;ll need a similar construct for things in parentheses, and while
we&#8217;re at it a &#8220;this string should be spaced out&#8221; construct wouldn&#8217;t
hurt either:</p>

<pre><code>&gt; symbol s = spaced $ string s

&gt; parens = between (symbol "(") (symbol ")")
</code></pre>

<p>Here&#8217;s a few example expressions to &#8220;sketch out&#8221; what the language
should look like:</p>

<p>The identity function:</p>

<pre><code>\x. x
</code></pre>

<p>A sample let expression:</p>

<pre><code>let id = \x. x in
id 5
</code></pre>

<p>Some math:</p>

<pre><code>\x. x * 3 + 2
</code></pre>

<p>Closures</p>

<pre><code>\x. (\y. x+y)
</code></pre>

<p>From this, we can see that there are only two keywords, &#8220;let&#8221; and
&#8220;in&#8221;. We&#8217;ll define those now:</p>

<pre><code>&gt; letKW = try $ do string "let"
&gt;                  notFollowedBy alphaNum

&gt; inKW = try $ do string "in"
&gt;                 notFollowedBy alphaNum

&gt; keywords = ["in", "let"]
</code></pre>

<p>A &#8220;this is a keyword&#8221; test will also be useful:</p>

<pre><code>&gt; isKW c = null ([c] \\ keywords)
</code></pre>

<p>Pretty much entirely stolen from the code for Parsec&#8217;s token parser
library.</p>

<pre><code>&gt; kwfail f = do{ x &lt;- f
&gt;              ; if isKW x
&gt;                then unexpected ("reserved word '" ++ x ++ "'")
&gt;                else return x
&gt;              }
</code></pre>

<p>Variable names are pretty simple, just have to check that the
identifier we&#8217;ve parsed is not a keyword.</p>

<pre><code>&gt; var = spaced $ do
&gt;                name &lt;- kwfail ident
&gt;                return $ EVar name

&gt; ident = do
&gt;         c &lt;- letter &lt;|&gt; char '_'
&gt;         cs &lt;- many (letter &lt;|&gt; char '_' &lt;|&gt; digit)
&gt;         return (c:cs)
</code></pre>

<p>We&#8217;re going to have literal integer values, which are pretty
straightforward except that we need to convert the value into an
integer when putting it in the ast.</p>

<pre><code>&gt; literal = spaced $ do
&gt;                    n &lt;- many1 digit
&gt;                    return $ Con ((read n)::Int)
</code></pre>

<p>We&#8217;re going to have two arithmetic operations, addition and
multiplication. Just to be fancy, we&#8217;ll abstract out the process of
recognizing an operator. The following code is a function that takes a
symbol and the AST representation and generates a function that, given
a left and right value, generates the AST for that operation.</p>

<pre><code>&gt; mkOp sym val = do
&gt;      symbol sym
&gt;      return (\l r -&gt; EOp val l r)
</code></pre>

<p>Now we can trivially define operators for addition and multiplication
(and anything else, when we need to):</p>

<pre><code>&gt; add = mkOp "+" Add
&gt; mul = mkOp "*" Mul
</code></pre>

<p>Order of operations can be tricky here. The standard &#8220;definition&#8221;
(stolen from wikipedia) looks like this:</p>

<pre><code>expression ::= additive-expression
additive-expression ::= multiplicative-expression ( '+' multiplicative-expression ) *
multiplicative-expression ::= primary ( '*' primary ) *
primary ::= '(' expression ')' | NUMBER | VARIABLE
</code></pre>

<p>Unfortunately, it&#8217;s left recursive, which will throw Parsec into an
infinite loop. Fortunately, there&#8217;s tools to deal with this, namely
<code>chainl1</code>. Our arithmetic expression looks pretty similar to the
above, once that&#8217;s taken into account:</p>

<pre><code>&gt; arithExpr    = arithTerm   `chainl1` add
&gt; arithTerm    = arithFactor `chainl1` mul
&gt; arithFactor  = parens aexpr &lt;|&gt; var &lt;|&gt; literal
</code></pre>

<p>Obviously we need a definition for an expression. Since we&#8217;re only
concerned with what is useful in the context of arithmetic
expressions, we&#8217;ll limit what can happen here to the things that could
have an arithmetic value.</p>

<pre><code>&gt; aexpr = spaced $ do
&gt;   n &lt;- (try app) &lt;|&gt; (try $ parens app) &lt;|&gt; arithExpr &lt;|&gt; literal &lt;|&gt; var &lt;|&gt; parens aexpr
&gt;   return n
</code></pre>

<p>A function application is composed of a (parenthesized) lambda
expression or variable on the left and an arithmetic expression on the
right.</p>

<pre><code>&gt; app = do
&gt;   f &lt;- (parens lam) &lt;|&gt; var
&gt;   x &lt;- (try $ parens arithExpr) &lt;|&gt;
&gt;        (try $ parens app)       &lt;|&gt;
&gt;        var                      &lt;|&gt;
&gt;        literal
&gt;   return $ App f x
</code></pre>

<p>A let expression binds a var to either a value or a lambda
expression. Nested let expressions are allowed, but we have to take
care to ensure that ultimately an arithmetic expression is
evaluated. We&#8217;re also going to allow multiple bindings in a single
let, immediately desugaring them into equivalent nested let
expressions. Note that, unlike in Haskell, the order of variable
naming is relevant. Fixing that is an exercise left to the reader.</p>

<p>Sample desugaring:</p>

<pre><code>let f = 5
    g = \x. x + x in
    g f

let f = 5 in
let g = \x. x + x in
g f
</code></pre>

<p>First, we&#8217;ll start with the name binding. To aid in using this for our
syntactic sugar, it produces a (Var, Exp) pair for the expression
bound to a given name:</p>

<pre><code>&gt; binding = do
&gt;   (EVar v) &lt;- var
&gt;   spaced (char '=')
&gt;   x &lt;- aexpr &lt;|&gt; lam &lt;|&gt; var &lt;|&gt; literal
&gt;   return $ (v,x)
</code></pre>

<p>Desugaring the lets is as simple as taking a list of the binding
results, along with the eventual body, and walking the list to nest
each binding in the let expression for the binding before it. For
completeness, we&#8217;ll handle the empty list case as well, even though it
won&#8217;t be permitted by the parser:</p>

<pre><code>&gt; desugarLets :: [(Var,Exp)] -&gt; Exp -&gt; Exp
&gt; desugarLets [] b         = b
&gt; desugarLets ((v,x):[]) b = Let v x b
&gt; desugarLets ((v,x):xs) b = Let v x (desugarLets xs b)

&gt; letexpr = do
&gt;   spaced letKW
&gt;   xs &lt;- sepBy1 binding (newline &lt;|&gt; char ';')
&gt;   spaced inKW
&gt;   many $ newline &lt;|&gt; char ';'
&gt;   b &lt;- letexpr &lt;|&gt; aexpr
&gt;   return (desugarLets xs b)
</code></pre>

<p>A lambda expression starts with a backslash, introduces a variable
name, and has either a let expression, a raw arithmetic expression, or
another lambda expression for its body.</p>

<pre><code>&gt; lam = do
&gt;   symbol "\\"
&gt;   (EVar v) &lt;- var
&gt;   symbol "."
&gt;   x &lt;- letexpr &lt;|&gt; (try aexpr) &lt;|&gt; (try app) &lt;|&gt; lam &lt;|&gt;
&gt;        parens lam
&gt;   return $ Lam v x
</code></pre>

<p>We&#8217;ll need this function later on to ease the process of running
functions over the parser&#8217;s output.</p>

<pre><code>&gt; runwith :: Parser a -&gt; (a -&gt; b) -&gt; String -&gt; Either ParseError b
&gt; runwith p conv input
&gt;         = case (parse p "" input) of
&gt;                 Left err -&gt; Left err
&gt;                 Right x  -&gt; Right $ conv x
</code></pre>

<p>Finally, we have a simple function to run a parser and print the
output.</p>

<pre><code>&gt; runIO :: Show a =&gt; Parser a -&gt; String -&gt; IO ()
&gt; runIO p input
&gt;         = case (parse p "" input) of
&gt;             Left err -&gt; do{ putStr "parse error at "
&gt;                           ; print err
&gt;                           }
&gt;             Right x  -&gt; print x
</code></pre>

<p>Next time, we&#8217;ll start working on an llvm-based simple calculator.</p>
 <div class='series_links'> <a href='http://blog.finiteimprobability.com/2009/11/25/lambda-calculus-compiler-part-ii-wading-in-with-arithmetic/' title='Lambda Calculus compiler, Part II: Wading in with arithmetic'>Next in series</a></div>]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/11/17/a-compiler-for-lambda-calculus-to-llvm-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Experience writing a ray tracer in Haskell</title>
		<link>http://blog.finiteimprobability.com/2009/06/18/experience-writing-a-ray-tracer-in-haskell/</link>
		<comments>http://blog.finiteimprobability.com/2009/06/18/experience-writing-a-ray-tracer-in-haskell/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 02:25:53 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[haskell]]></category>
		<category><![CDATA[raytracing]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/2009/06/18/experience-writing-a-ray-tracer-in-haskell/</guid>
		<description><![CDATA[I promised I would give a bit more in the way of details on the ray tracer. Here they are.

During the last three weeks of the term we were directed to come up with a &#8220;term project&#8221; for the functional programming course. [1] We needed to come up with something that was interesting and exercised [...]]]></description>
			<content:encoded><![CDATA[<p>I promised I would give a bit more in the way of details on the ray tracer. Here they are.</p>

<p>During the last three weeks of the term we were directed to come up with a &#8220;term project&#8221; for the functional programming course. [1] We needed to come up with something that was interesting and exercised the features we&#8217;d been learning about all term. I&#8217;ve wanted to write a ray tracer for a while now, so I picked that. The assignment, as I gave it to myself, was to write a minimal but complete ray tracer and report on the experience of profiling and parallelizing it.</p>

<p>The ray tracer itself took around 30 hours of work. Partially this was me struggling with the language, partially me struggling with the topic, and partially me being picky and/or making and fixing bad design decision. When I turned it in it would only do spheres in flat colors and reflection (or a combination) with specular and diffuse lighting. I&#8217;ve been working on transparency and diffraction, but that code isn&#8217;t really worth showing off yet. I&#8217;ll eventually do some more complicated shapes and may explore more interesting materials.</p>

<p>Writing a ray tracer in Haskell was a &#8230; luxurious experience. The heart of a ray tracer is almost entirely math, and Haskell represents that <em>very</em> well. The only real difference between my Haskell code and the math behind it was some additional let bindings I introduced while profiling. I enjoyed being able to avoid unnecessary computations implicitly through laziness, instead of explicitly through conditionals, as I would have needed to do in other languages.</p>

<p>I originally planned to spend a few hours working on parallelization. I started playing around with it for fun while I was waking up with coffee one morning. Half an hour and 53 characters later I had around a 40% speedup on two cores. In this, Haskell kind of ruined the project for me. It was too easy to introduce parallelization into the program and have it <em>just work</em>. A very helpful co-worker ran some benchmarks for me on a few systems. Here&#8217;s the performance chart.</p>

<p><a href="/wp-content/uploads/2009/06/performance-chart.png"><img src="/wp-content/uploads/2009/06/performance-chart.png" width=450 height=300>Performance chart</img></a></p>

<p>These results are rather informal, but you can see the impressive increases from parallel execution. I&#8217;m not entirely sure what is going on at the eight core mark, but I think it has something to do with an issue with (GHC only?) multicore support on Linux.</p>

<p>If you&#8217;d like to point and laugh at my code, you can find it <a href="/wp-content/uploads/2009/06/project.zip">here</a>. I compile it on ghc with &#8220;ghc -O -threaded -o ray &#8211;make Main.lhs&#8221;. Comments are very welcome.</p>

<p>[1] Taught by <a href="http://web.cecs.pdx.edu/~mpj/">Mark Jones</a> (the initial author of Hugs) and <a href="http://web.cecs.pdx.edu/~sheard/">Tim Sheard</a> (who is just FP brilliant) <em>amazing</em> class.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/06/18/experience-writing-a-ray-tracer-in-haskell/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>One of my term projects&#8230;</title>
		<link>http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/</link>
		<comments>http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 15:24:08 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=41</guid>
		<description><![CDATA[199 Lines of Haskell, about 30 hours of work. My first ever ray tracer! My first ever considerable Haskell program! Runs in parallel for ~40% speedup. More details to come.
]]></description>
			<content:encoded><![CDATA[<p>199 Lines of Haskell, about 30 hours of work. My first ever ray tracer! My first ever considerable Haskell program! Runs in parallel for ~40% speedup. More details to come.</p>


<a href='http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/helix/' title='helix'><img width="150" height="150" src="http://blog.finiteimprobability.com/wp-content/uploads/2009/06/helix-150x150.png" class="attachment-thumbnail" alt="" title="helix" /></a>
<a href='http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/spheres/' title='spheres'><img width="150" height="150" src="http://blog.finiteimprobability.com/wp-content/uploads/2009/06/spheres-150x150.png" class="attachment-thumbnail" alt="" title="spheres" /></a>
<a href='http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/torture/' title='torture'><img width="150" height="150" src="http://blog.finiteimprobability.com/wp-content/uploads/2009/06/torture-150x150.png" class="attachment-thumbnail" alt="" title="torture" /></a>

]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/06/05/one-of-my-term-projects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>March in summary</title>
		<link>http://blog.finiteimprobability.com/2009/03/06/march-in-summary/</link>
		<comments>http://blog.finiteimprobability.com/2009/03/06/march-in-summary/#comments</comments>
		<pubDate>Fri, 06 Mar 2009 19:01:18 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[compiler]]></category>
		<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/2009/03/06/march-in-summary/</guid>
		<description><![CDATA[Wow, a lot happened last month. Since this term for school is coming to a close, the work involved is piling up. As such I haven&#8217;t really been able to get much done for my projects. In addition to that, I started an internship at the very end of the month. I&#8217;m working as a [...]]]></description>
			<content:encoded><![CDATA[<p>Wow, a lot happened last month. Since this term for school is coming to a close, the work involved is piling up. As such I haven&#8217;t really been able to get much done for my projects. In addition to that, I started an internship at the very end of the month. I&#8217;m working as a tester for <a href="http://www.weogeo.com">weogeo</a>. They run a &#8220;geographic data marketplace&#8221;, which allows people to buy and sell pretty much any information with locations attached to it. (like geological survey results and census data)</p>

<p>The game development project has pretty well stalled out. I&#8217;m realizing now that my decision to develop it in flash was partly motivated by a pie-in-the-sky dream of earning money from it. Now that I&#8217;m working, this isn&#8217;t really as pressing of a motivation and the problems of working with in flash are starting to outweigh the benefits.</p>

<p>My compiler project is coming along a bit better. I have a lexer, written in <a href="http://www.haskell.org/alex/">alex</a> for JavaScript. It doesn&#8217;t support unicode in the identifiers, but that is more of the same from the compiler&#8217;s viewpoint. I&#8217;ve been playing around with an abstract syntax tree to use in the parsing phase. OOP implementations of this can take advantage of inheritance to encode things like &#8220;a bit operation is an and, or, or xor of two expressions&#8221; in an inheritance relationship and use that to ensure valid trees are created. Since Haskell doesn&#8217;t (easily) support this kind of inheritance, we instead have to flatten things out and do this with the functions that construct the AST instead of encoding it in the type of the AST. Well, that or write a giant pile of data type definitions to do the encoding manually, which produces a bunch of almost-redundant constructors and a lot of busywork.</p>

<p>I&#8217;m probably going to go the &#8220;flat AST and functions to ensure valid construction&#8221; route. Either way I&#8217;m planning to write the parser twice. One version will use happy (Haskell&#8217;s equivalent to yacc) and one using Parsec (a nifty parser combinator library). So, I&#8217;d like the AST to be easy to work with. We&#8217;ll see how that goes.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/03/06/march-in-summary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Left 4 Dead: Tank Misconceptions&#8230;</title>
		<link>http://blog.finiteimprobability.com/2009/02/02/left-4-dead-tank-misconceptions/</link>
		<comments>http://blog.finiteimprobability.com/2009/02/02/left-4-dead-tank-misconceptions/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 00:07:59 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[left4dead]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/?p=38</guid>
		<description><![CDATA[This is a repost of something I wrote for the forums. Now that it&#8217;s lost to that refuse heap I thought it could also wait out its days in solitude here. If you haven&#8217;t played the video game &#8220;Left 4 Dead&#8221;, this will probably be just about unintelligible.

It&#8217;s understandable that a lot of people don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>This is a repost of something I wrote for the forums. Now that it&#8217;s lost to that refuse heap I thought it could also wait out its days in solitude here. If you haven&#8217;t played the video game &#8220;Left 4 Dead&#8221;, this will probably be just about unintelligible.</p>

<p>It&#8217;s understandable that a lot of people don&#8217;t really understand the Tank. He&#8217;s a rare spawn in general, and splitting the chance to play as him with three other people means little chance to practice. This affects the survivors too, as his scarcity makes getting experience dealing with him more difficult. That said, here&#8217;s a bunch of things about the Tank that people either don&#8217;t know, don&#8217;t think about, or are just flat out wrong on:</p>

<ol>
<li>We should run like headless chickens:</li>
</ol>

<p>This is just about never the solution, especially on VS. In most Tank encounters the real problem isn&#8217;t the Tank, it&#8217;s the other infected. Don&#8217;t panic and run like nuts, carefully stay out of his range and concentrate on keeping the area clear of other infected. They move faster than you do, the Tank (usually) doesn&#8217;t. A single normal infected can mean the difference between escaping unscathed and as that big wall of muscle turns you into a pothole.</p>

<p>The other problem here is that, while everyone is busy running away, they aren&#8217;t shooting him. The real approach to handling a Tank is to work as a group to keep your distance from him, and whoever isn&#8217;t being chased by him is shooting him in the ass. There&#8217;s two reasons for this: A) it does damage, which will eventually kill him (that&#8217;s the point, remember), and B) being shot temporarily slows him down, so being shot continuously will give his pursuee breathing room. This is key for saving someone who is &lt; 50 health, or who runs into an unexpected obstruction. Try it, it works.</p>

<ol>
<li>Set him on fire, then run like headless chickens:</li>
</ol>

<p>In addition to all of the problems above, (in co-op only) setting the Tank on fire makes him run faster, which also means he runs faster than you. If your teammates are busy running in three separate directions he can now easily catch up to you and turn you into a pothole. Fire is great insurance against the Tank, but it won&#8217;t kill him fast enough to make a difference on all but the easiest difficulties. Fire+scatter is just as lethal in VS as scattering is.</p>

<ol>
<li>As Tank, the rock throw is useless:</li>
</ol>

<p>This just isn&#8217;t true. In some situations where the survivors are grouped together somewhere that puts you in easy range of a molotov and/or spray of bullets, it&#8217;s better to hang back and go for some rock throws from a safe distance. Picking up a rock tends to make anyone you aren&#8217;t pointed at brave, and makes them forget that the direction of the throw isn&#8217;t determined until just before it happens. Learn to grab a rock and do a last second turn and throw at someone pelting you in the back. It&#8217;s pretty much the only option to handle survivors that are kiting you well if your buddies let you down.</p>

<ol>
<li>As a Tank, I should just charge in and do some DAMAGE!!!:</li>
</ol>

<p>No, you shouldn&#8217;t. Well, maybe, but it isn&#8217;t that simple. You start out with a lot of rage time (I think 40 seconds). Take advantage of it. If the survivors keep advancing, look for the best spot to hit them (tight hallways) and bide your time. At the least, give your teammates time to spawn in and help you. If need be, try to get a distance rock throw in and retreat with your freshly regenerated rage timer. Like any other class in the game, the Tank depends on teamwork to get the job done. The only reason this doesn&#8217;t seem true is also the point of this post: statistically, no one knows how to deal with a Tank.</p>

<p>The other problem with charging in is that it&#8217;s predictable, and can be costly. On the NM5 roof the absolute worst thing to do is charge right through minigun fire at the survivors. Congrats on losing half of your health before you even get close to anyone. You&#8217;ll probably get set on fire too. If you hang back, especially if you run around the roof for an alternate route, you can hit them from a better position and give your teammates time to distract them. A survivor ready to throw a molly looks pretty distinctive, and there&#8217;s nothing funnier than owning up as a Tank because you waited long enough for a hunter to pounce the guy trying to set you on fire.</p>

<p><em>Parking a tank is pretty much sitting somewhere and letting your rage run out, so the tank remains stationary until triggered by the survivors, like in Campaign. The most notable place to do this is in NM4, in the final safe room. Not very honorable, but if the survivors are vent camping (behind the elevator) with a full stock of mollies and auto shotties, it&#8217;s just the way to stick it to them.</em></p>

<p>(Portion in *&#8217;s is courtesy of OmNomNomNom, thanks)</p>

<ol>
<li>As a Tank, I should hit anything I can reach:</li>
</ol>

<p>Usually, this is true, but if one of your teamates has pounced or grabbed a survivor your new priority is to protect that situation at all costs. In practice, a Hunter pounce does more DPS than Tank punches unless you consistently land every single punch as fast as you can swing (hint: no). If one of your teammates has a survivor, do your best to keep the rest busy and away from him. At the very least, don&#8217;t knock him free. Given that you have the ability to hit anyone else, you&#8217;re cutting into the team&#8217;s DPS by doing so.</p>

<ol>
<li>As a Tank, I should hurry up or else I&#8217;ll lose control:</li>
</ol>

<p>This can be a good thing. IMO they shouldn&#8217;t have put individual scores for infected in L4D, it just encourages people to play for their score instead of for the team&#8217;s benefit. Sometimes you need to wait for the right moment to strike, and sometimes that moment is after your rage timer expires. In my opinion it&#8217;s usually better to run in rather than let the AI take over, so if you&#8217;re the second one with it take your best chance within the rage timer. The only time this doesn&#8217;t work is if you&#8217;re trying to park him somewhere, but that&#8217;s obvious.</p>

<p>Other important facts:</p>

<ol>
<li><p>The Tank&#8217;s swing takes a little time to connect. Try to lead your swing a bit if you&#8217;re running up to a survivor. Otherwise you give them a little time to get out from in front of you before they get hit.</p></li>
<li><p>The rock throw doesn&#8217;t auto fire if it&#8217;s held down after it charges. You have to spam the button if you&#8217;re trying to bombard the survivors.</p></li>
<li><p>In co-op, fire makes the Tank run faster. Be sure you have plenty of space to run around him, and are able to kite him around something while everyone else shoots him. In VS, it&#8217;s just about a win-win, just make sure you don&#8217;t have to run through the fire too much.</p></li>
<li><p>Vents <em>and windows</em> seriously slow down the Tank. Abuse/avoid this as appropriate. <em>In co-op NM5, jumping through the window gives you a good 10-20s of shooting gallery time while he squeezes his fat ass through</em> (portion in *&#8217;s courtesy of thomasng1989)</p></li>
<li><p>The AI Tank likes to climb stuff. If you&#8217;re kiting him around something watch for him to try and shortcut over it.</p></li>
<li><p>Meleeing an AI Tank in the back will cause him to focus on you. Use this to get his attention away from a downed survivor. Melee him and run away shooting to keep his attention. Only do this if the other two survivors are there to fire on him as well, otherwise it&#8217;s probably suicide. This is just about the only way to save someone on Expert.</p></li>
<li><p>You can shoot the rock. If you&#8217;re out in the open, do this. If you&#8217;ve got any kind of cover, that&#8217;s probably the better alternative. It takes a few hits to break, so don&#8217;t be surprised if this fact doesn&#8217;t always give you rock immunity.</p></li>
<li><p>Explosions (propane tanks, pipe bombs) stagger the Tank. They also do a decent bit of damage. Hitting him with a pipe bomb probably won&#8217;t happen, but if you can get him to run over a propane tank or three when you shoot them it can do a lot to help.</p></li>
<li><p>Unless you&#8217;re in green (<em>correction: above 40 health</em>), he runs faster than you. So if you&#8217;re in anything less than green the Tank music is your cue to heal up, get your pills ready, or put some distance between you and him and make peace with your maker. <em>As a Tank, be aware that there&#8217;s a ten point range where someone having a yellow outline does not mean you can catch them.</em></p></li>
</ol>

<p>Sections in *&#8217;s courtesy of madcap, among others.</p>

<ol>
<li><p>Hitting survivors with an object (car, tree trunk, generator, anything outlined in red) is the fastest way to take them from green to incap. Go for it when possible, but watch out for situations (like the NM2 room below the generator room) where survivors can easily duck behind obstructions.</p></li>
<li><p>If you aren&#8217;t the Tank, he needs you to help slow the survivors down. They run faster than he does, but not if they&#8217;re Boomered and surrounded by commons. Likewise it&#8217;s pretty easy to meet the survivors at their target when they&#8217;re running to help a buddy who&#8217;s been pinned or tongued &#8230; or hit them with a rock while they&#8217;re doing so.</p></li>
<li><p>Avoid fire at all costs. Many survivors will throw their molotov ahead of you a bit early to give themselves more room to run. Watch their outlines; if they have the molly out look for the opportunity to stop short of running into flames. If you are on fire, you&#8217;ve only got a limited amount of time to go do some damage, make everything you do count.</p></li>
<li><p>Don&#8217;t be discouraged if you don&#8217;t do well. Sometimes you get outplayed, or your teammates don&#8217;t help, or you just get unlucky. If you tried to do what I outlined in this guide and still didn&#8217;t do much damage, examine how you (or your teammates) deviated from the suggestions or maybe how the survivors really did outplay you. I very probably do not know everything about the Tank, maybe you can learn something from your defeat and have something to share. Above all, anyone balling you out for not doing well is a punk or just a poor sport, don&#8217;t bother listening. Take constructive criticism and spend some time thinking about what (if anything) went wrong.</p></li>
<li><p>Memorize the finale sequence, and be prepared to help the Tank after the second infected wave. If you get the Tank, make sure to spawn your current infected in before he gets control, a bot infected is better than none at all.</p></li>
<li><p>If the survivors are doing a great job staying out of your reach, look for a good way to quickly get behind cover. Give your teammates a chance to distract them or give them a chance to slip up and give you an opening.</p></li>
<li><p>As survivors, be sure to have at least one person with an automatic weapon (Uzi/M16). Since every bullet slows the tank down on impact, these guns do a great job of keeping him away from everyone else. Also, take advantage of the minigun any time you can. It does great damage and also works to slow him down.</p></li>
<li><p>In stages where it is applicable (namely, NM4/NM5), look for opportunities to knock survivors off the edge of the building. This is a one-hit death for them, and can often be achieved by strafing as you move to position yourself opposite the edge of the building from the survivor. As a survivor, prefer taking a hit from the Tank to putting yourself between him and the ledge. Get off the top of the building (with the mini-gun nest) in NM5 as soon as you can to avoid being punted off. Any of the elevated areas in this level are dangerous, but it is usually difficult for a Tank to position himself to knock you from the lower levels.</p></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/02/02/left-4-dead-tank-misconceptions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resolutions update, one month</title>
		<link>http://blog.finiteimprobability.com/2009/01/28/resolutions-update-one-month/</link>
		<comments>http://blog.finiteimprobability.com/2009/01/28/resolutions-update-one-month/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 20:06:13 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/2009/01/28/resolutions-update-one-month/</guid>
		<description><![CDATA[I&#8217;m going to try and keep up with what I&#8217;ve done towards these
resolutions at the end of each month. Hopefully this will help me stay
on task. Here&#8217;s what I&#8217;ve done so far:


On the game development front: I spent a bit of time this month trying
to come up with ways to get a bit of extra [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to try and keep up with what I&#8217;ve done towards these
resolutions at the end of each month. Hopefully this will help me stay
on task. Here&#8217;s what I&#8217;ve done so far:</p>

<ul>
<li><p>On the game development front: I spent a bit of time this month trying
to come up with ways to get a bit of extra money. One of the ideas was
to work up some simple web games (in Flash) and try to get them
published. I wouldn&#8217;t mind eventually doing my game project in this,
and am learning to use the Flex compiler to write Flash projects in
pure ActionScript 3. If you&#8217;re interested, I found a good
reference
<a href="http://www.senocular.com/flash/tutorials/as3withmxmlc/">here</a>.</p></li>
<li><p>On the Haskell/compiler front: I&#8217;m considering doing an AS3->Flash
compiler in Haskell. The mxmlc compiler provided with Flex is written
in Java, which means each recompile gets to enjoy the jvm startup
time. Anyways, it would be a fun side project that
probably will result in a half-finished compiler not suitable for
anyone&#8217;s use. I&#8217;m sure I&#8217;ll learn something though.</p></li>
<li><p>On the productivity front: Things are going ok here. I could be doing
better, but I&#8217;m satisfied with what&#8217;s happened so far.</p></li>
</ul>

<p>Obviously the &#8220;more blogging&#8221; goal is happening so far.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/01/28/resolutions-update-one-month/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I&#8217;ve lost my mind</title>
		<link>http://blog.finiteimprobability.com/2009/01/07/ive-lost-my-mind/</link>
		<comments>http://blog.finiteimprobability.com/2009/01/07/ive-lost-my-mind/#comments</comments>
		<pubDate>Wed, 07 Jan 2009 23:39:31 +0000</pubDate>
		<dc:creator>Adam Jones</dc:creator>
				<category><![CDATA[games]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[starbound]]></category>

		<guid isPermaLink="false">http://blog.finiteimprobability.com/2009/01/07/ive-lost-my-mind/</guid>
		<description><![CDATA[After spending some time thinking about what is going wrong with this
game, I came to two conclusions:


Repl-based development doesn&#8217;t work for me. I ended up spending a lot
of time working my way into an inconsistent game state without know it,
so most of my time savings were spent figuring out how I&#8217;d borked things
on the next [...]]]></description>
			<content:encoded><![CDATA[<p>After spending some time thinking about what is going wrong with this
game, I came to two conclusions:</p>

<ol>
<li><p>Repl-based development doesn&#8217;t work for me. I ended up spending a lot
of time working my way into an inconsistent game state without know it,
so most of my time savings were spent figuring out how I&#8217;d borked things
on the next restart.</p></li>
<li><p>Haskell is just too damn interesting. Every time I tried to work on
the project I found myself goofing off there.</p></li>
</ol>

<p>Obviously, these points say much more about me than the tools I was
using, but the simple fact was that I still wasn&#8217;t getting much done. I
actually really liked how clean the more functional bits of my original
game code were, so I&#8217;m taking the plunge and switching to Haskell for my
game.</p>

<p>Since I&#8217;ve been wanting to dig deep into Haskell for a while this should
really push me there. So far just trying to express something as simple
as &#8220;a game unit can possibly target something targettable&#8221; has been a
deeper rabbit hole than I thought, and now that I think about it my
current solution won&#8217;t work. Luckily the new one is simpler.</p>

<p>I&#8217;m well aware that this will probably mean the death of this game, but
it already seemed to be in critical condition, and either way the
learning experience would be good. Stay tuned to see what happens.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.finiteimprobability.com/2009/01/07/ive-lost-my-mind/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
