<?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>My Diversions &#187; Computer Science</title>
	<atom:link href="http://www.kablambda.org/blog/category/computer-science/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kablambda.org/blog</link>
	<description>Notes on things I'm thinking and doing</description>
	<lastBuildDate>Tue, 20 Oct 2009 11:31:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Functional Programming on Android</title>
		<link>http://www.kablambda.org/blog/2009/07/27/functional-programming-on-android/</link>
		<comments>http://www.kablambda.org/blog/2009/07/27/functional-programming-on-android/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 13:57:08 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[CAL and Open Quark]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=99</guid>
		<description><![CDATA[I&#8217;ve integrated CAL with a variety of Java based frameworks/environments: Tapestry, GWT and Google AppEngine for instance.

Recently someone asked on the CAL Google Group whether CAL programs could run on Android mobile devices. Android doesn&#8217;t use a standard JVM, it uses Dalvik, and it provides a subset of the normal JRE library.

I have put together [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve integrated <a href="http://openquark.org">CAL</a> with a variety of Java based frameworks/environments: <a href="http://www.kablambda.org/blog/2007/09/24/cal-and-the-tapestry-5-tutorial/">Tapestry</a>, <a href="http://www.kablambda.org/blog/2008/03/15/gwt-as-a-cal-client/">GWT</a> and <a href="http://www.kablambda.org/blog/2009/04/27/cal-hangman-on-google-appengine-part-1/">Google AppEngine</a> for instance.</p>

<p>Recently someone asked on the <a href="http://groups.google.com/group/cal_language">CAL Google Group</a> whether CAL programs could run on Android mobile devices. Android doesn&#8217;t use a standard JVM, it uses <a href="http://en.wikipedia.org/wiki/Dalvik_virtual_machine">Dalvik</a>, and it provides a subset of the normal JRE library.</p>

<p>I have put together a trivial proof of concept to show that CAL does indeed work on Android &#8212; although it doesn&#8217;t cover a great deal of CAL&#8217;s runtime behaviour, so there might be problems with larger programs which I haven&#8217;t detected.</p>

<p>My sample application just accumulates keypresses and displays the resulting string.</p>

<h2>The Android Activity</h2>

<p>This class delegates calls to <code>onCreate</code> and <code>onKeyUp</code> to CAL functions.</p>

<p>The state of the application (a <code>String</code> in this case) is initialised to the value returned by the CAL <code>onCreate</code> function, and is then passed to and returned from the <code>onKeyUp</code> function.</p>

<pre><code>public class CalActivity extends Activity {
    private ExecutionContext ec;
    private TextView tv;
    private String state = null;

    public CalActivity() {
        System.setProperty("org.openquark.cal.machine.lecc.non_interruptible", "true");
        ec = StandaloneRuntime.makeExecutionContext(CalActivity.class);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tv = new TextView(this);
        try {
            state = Test.onCreate(CAL_Opaque.make(this), CAL_Opaque.make(savedInstanceState), ec);
            tv.setText(state.toString());
        } catch (CALExecutorException e) {
            tv.setText(e.getMessage());
        }
        setContentView(tv);
    }

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        char c = (char)event.getUnicodeChar();
        // ignore events which aren't characters
        if (c != 0) {
            try {
                state = Test.onKeyUp(CAL_Opaque.make(this), c, state, ec);
            } catch (CALExecutorException e) {
                tv.setText(e.getMessage());
            }
            tv.setText(state.toString());
            return true;
        }
        return super.onKeyUp(keyCode, event);
    }
}
</code></pre>

<h2>The CAL Module</h2>

<pre><code>module Org.Kablambda.Android.Test;

... imports omitted ...

onCreate :: Activity -&gt; Bundle -&gt; String;
public onCreate activity bundle = "Hello from CAL!\n";

onKeyUp :: Activity -&gt; Char -&gt; String -&gt; String;
public onKeyUp activity ch s = s ++ (fromChar ch);
</code></pre>

<p><code>Activity</code> and <code>Bundle</code> are declared as foreign types, but don&#8217;t have any functions defined on them at present.</p>

<h2>Modifications to the build process</h2>

<p>I added some new targets to the standard <code>build.xml</code> file created by the android SDK.</p>

<pre><code>&lt;property name="quark.dir" location="${user.home}/dev/tools/cal-1.7.1" /&gt;
&lt;property name="moduleName" value="Org.Kablambda.Android.Test"/&gt;
&lt;property name="className" value="org.kablambda.android.Test"/&gt;
</code></pre>

<p>These properties set the location of our CAL installation, the name of the CAL module we want to call from Java, and the name of the class we want that module&#8217;s functions to be exposed in.</p>

<p>The <code>copy-quark-jars</code> target copies the jar files needed by CAL at runtime. They are copied into a temporary directory.</p>

<pre><code>&lt;target name="copy-quark-jars"&gt;
    &lt;mkdir dir="tmp"/&gt;
    &lt;copy
            todir="tmp"
            flatten="true"&gt;
          &lt;fileset dir="${quark.dir}/Quark/bin/java/release"&gt;
            &lt;include name="**/calLibraries.jar" /&gt;
            &lt;include name="**/calRuntime.jar" /&gt;
            &lt;include name="**/calUtilities.jar" /&gt;
          &lt;/fileset&gt;
          &lt;fileset dir="${quark.dir}/Quark/lib/Resources/External/java/"&gt;
            &lt;include name="**/icu4j.jar" /&gt;
            &lt;include name="**/log4j.jar" /&gt;
          &lt;/fileset&gt;
        &lt;/copy&gt;
  &lt;/target&gt;
</code></pre>

<p>The <code>build-quark-standalone</code> target compiles the CAL workspace <code>workspace.cws</code> into a jar file. This workspace must contain the module specified above and its dependencies. This target assumes that <code>${quarkdir}/Quark</code> is on the <code>PATH</code>.</p>

<pre><code>  &lt;target name="build-quark-standalone" depends="copy-quark-jars"&gt;
    &lt;exec executable="quarkc.sh"&gt;
        &lt;arg value="workspace.cws"/&gt;
        &lt;arg value="-lib"/&gt;
        &lt;arg value="${moduleName}"/&gt;
        &lt;arg value="public"/&gt;
        &lt;arg value="${className}"/&gt;
        &lt;arg value="tmp/calmodule.jar"/&gt;
        &lt;arg value="-src"/&gt;
        &lt;arg value="calmodule-src.zip"/&gt;
        &lt;env key="QUARK_CP" value="src:bin:${sdk-location}/platforms/android-1.5/android.jar"/&gt;
    &lt;/exec&gt;
  &lt;/target&gt;
</code></pre>

<p>Because several of the CAL jars contain duplicate files, which Android doesn&#8217;t tolerate, we merge all our jars into a single file, ignoring duplicates.</p>

<pre><code>&lt;target name="merge-jars" depends="build-quark-standalone"&gt;
    &lt;zip destfile="libs/cal.jar" duplicate="preserve"&gt;
        &lt;zipgroupfileset dir="tmp" includes="*.jar"/&gt;           
    &lt;/zip&gt;
&lt;/target&gt;
</code></pre>

<p>To deploy your application to the Android Emulator you need to run <code>ant merge-jars reinstall</code>.</p>

<p>Note that during the process of converting the <code>cal.jar</code> file to Dalvik bytecode you&#8217;ll see a large number of error messages like this:</p>

<pre><code>[apply] ...while processing com/ibm/icu/util/TimeZoneData.class
[apply] warning: Ignoring InnerClasses attribute for an anonymous inner class that doesn't come with an associated EnclosingMethod attribute. (This class was probably produced by a broken compiler.)
</code></pre>

<p>This is something to do with the rather old version of IBM&#8217;s <a href="http://site.icu-project.org/home">International Components for Unicode library</a> &#8212; it would be interesting to recompile CAL with a more recent version &#8212; or just recompiling that version of <code>icu4j</code> with the Sun compiler.</p>

<h2>Further Work</h2>

<p>The Android API needs to be exposed to CAL, and a Monad written to sequence Android API operations which have side effects. The <code>CalActivity</code> implementation should store the state as an opaque <code>CalValue</code>, so that implementations can choose what type to use for their state, and of course it needs to delegate all the possible events to CAl functions. There&#8217;s plenty of scope for more scaffolding on the CAL side.</p>

<p>As I don&#8217;t have an Android phone I doubt that I&#8217;ll do any further work on this &#8212; unless Dalvik gets an iPhone port <img src='http://www.kablambda.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/07/27/functional-programming-on-android/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Reconsidering my Combinators</title>
		<link>http://www.kablambda.org/blog/2009/05/25/reconsidering-my-combinators/</link>
		<comments>http://www.kablambda.org/blog/2009/05/25/reconsidering-my-combinators/#comments</comments>
		<pubDate>Mon, 25 May 2009 12:00:14 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[CAL and Open Quark]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=86</guid>
		<description><![CDATA[Since writing my set of function combinators for matching HTTP requests I&#8217;ve realised that there are better approaches.

While the combinators read nicely, once you start extracting attributes from the request things become messy, due to the hAnd combinator composing results as nested pairs.

Here&#8217;s an example:

skitchPutHandler =
    let
      [...]]]></description>
			<content:encoded><![CDATA[<p>Since writing my set of function combinators for matching HTTP requests I&#8217;ve realised that there are better approaches.</p>

<p>While the combinators read nicely, once you start extracting attributes from the request things become messy, due to the <code>hAnd</code> combinator composing results as nested pairs.</p>

<p>Here&#8217;s an example:</p>

<pre><code>skitchPutHandler =
    let
        storeImage p =
            let (p2, path) = p;
                (maybeContentType,imageData) = p2;
                ...
            in ...
    in
        matchMethod "PUT" `hThen` matchUrl "/skitch" `hThen`
            (getHeader "Content-Type") `hAnd` requireRawData `hAnd` requirePathInfo `hApply` storeImage;
</code></pre>

<p>Unpacking the values extracted from the request is cumbersome, and because many are <code>String</code>s, error prone.</p>

<p>A better approach is to simply use the <code>Maybe</code> monad with the same extraction functions:</p>

<pre><code>simpleSkitchPutHandler req =
    let
        maybeContentType = requireHeader "Content-Type" req;
        ...
    in
        matchMethod "PUT" req `anonymousBind` matchUrl "/skitch" req `anonymousBind`
            requireRawData req `bind` (\rawData -&gt;
            requirePathInfo req `bind` (\path -&gt;
            return $ storeImage path rawData (actualContentType path)));
</code></pre>

<p>Optional values are extracted in let expressions, and required values and tests are composed with the monadic <code>bind</code> operators in the main expression.
You can make the function a bit more concise and &#8216;point free&#8217; by writing a monad which composes the <code>Maybe</code> and <code>Reader</code> monads to supply the HTTP request parameter to functions implicitly:</p>

<pre><code>readerMonadSkitchPutHandler =
    let
        ...
    in
        runHttpRequestM (
        method "PUT" `anonymousBind` matchUrlM "/skitch" `anonymousBind`
            rawData `bind` (\rawData -&gt;
            pathInfo `bind` (\path -&gt;
            (optional (header "Content-Type")) `bind` (\maybeContentType -&gt;
            return $ storeImage path rawData (actualContentType path maybeContentType)))));
</code></pre>

<p>The function <code>optional</code> has the type <code>HttpRequestM a -&gt; HttpRequestM (Maybe a)</code>, that is, it allows a function to succeed by wrapping its result in a &#8216;Just&#8217;.</p>

<p>I&#8217;m not convinced that the improvement in readability gained by removing the request parameter is worth the increase in complexity.</p>

<p>So I&#8217;ll remove the combinators from my <code>Http</code> module and will rewrite Hangman using just the Maybe monad. I&#8217;ll keep the more complicated Monad on the back-burner in case I discover a compelling advantage.</p>

<p>I&#8217;d be interested to know what someone with a deeper understanding of functional programming would say.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/05/25/reconsidering-my-combinators/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CAL Hangman on GAE Part 2 &#8212; The Datastore</title>
		<link>http://www.kablambda.org/blog/2009/05/12/cal-hangman-on-gae-part-2-the-datastore/</link>
		<comments>http://www.kablambda.org/blog/2009/05/12/cal-hangman-on-gae-part-2-the-datastore/#comments</comments>
		<pubDate>Tue, 12 May 2009 12:48:48 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[CAL and Open Quark]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=83</guid>
		<description><![CDATA[Introduction

My implementation of Hangman has only very simple data storage requirements, so my CAL module Datastore doesn&#8217;t cover the entire capabilities of Bigtable.

All the application needs is to be able to save a Game instance, put the key of that instance into a cookie in the user&#8217;s browser, and then retrieve and update that instance [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>

<p>My implementation of Hangman has only very simple data storage requirements, so my CAL module <code>Datastore</code> doesn&#8217;t cover the entire capabilities of Bigtable.</p>

<p>All the application needs is to be able to save a <code>Game</code> instance, put the key of that instance into a cookie in the user&#8217;s browser, and then retrieve and update that instance as the user makes each guess, or delete it if the user chooses to restart the game.</p>

<p>Important unexplored areas are:</p>

<ul>
<li><p>The creation of entities having another entity as a parent. This is important in Bigtable, because a transaction can only operate on entities in the same &#8216;entity group&#8217; &#8212; that is, entities which share a common parent.</p></li>
<li><p>The persistence of references to other entities, and special treatment of these references when performing operations on the entity containing the reference &#8212; that is, there is no support for modelling relationships between entities.</p></li>
<li><p>No error handling support &#8212; any exception will result in a 500 response. In particular, <code>ConcurrentModificationException</code> should be treated differently, as this indicates that a transaction failed due to another transaction modifying the same records. A failure of this type should either be retried, or reported to the user in an application specific manner.</p></li>
<li><p>The module is limited to storing types with a single constructor, although there is no difficulty in extending this to support multiple constructor ADTs.</p></li>
</ul>

<p>It is implemented using the <a href="http://code.google.com/appengine/docs/java/javadoc/com/google/appengine/api/datastore/package-summary.html">low level api</a>, not JDO.</p>

<h2>Datastore Module</h2>

<p>The <code>Datastore</code> module provides a <code>Monad</code> instance for using the AppEngine data store, and a <code>Storeable</code> type class. The source is <a href="http://bazaar.launchpad.net/%7Etgdavies/cal-on-gae/main/annotate/head%3A/src/CAL/Org/Kablambda/AppEngine/Datastore.cal">here</a>.</p>

<h3>The Storeable Type Class</h3>

<p>Algebraic data types which need to be persisted must be instances of <code>Storeable</code>, which provides metadata needed to persist instances of the type. The metadata includes:</p>

<ul>
<li><p>The &#8216;kind&#8217; of the record &#8212; analogous to the name of the table to store instances of the type in, not to kind in the type theory sense.</p></li>
<li><p>The data store property names to use for each of the constructor arguments.</p></li>
</ul>

<p>When using CAL in statically compiled mode the names of types and the names of constructor parameters are not easily available at runtime. The constructor arguments could simply be stored in properties named <code>arg0...n</code>, but this would make querying and debugging more difficult.</p>

<pre><code>data public Store a = public Store kind :: String fields :: [String];

public class (Outputable a, Inputable a) =&gt; Storeable a where
    store :: a -&gt; Store a;
    ;
</code></pre>

<p>Note that the type parameter <code>a</code> is not used in the declaration of the constructor arguments &#8212; it simply labels the store to ensure that the store used with, for example <code>fromEntity</code> below, is consistent with the type of <code>Storeable</code> we are expecting <code>fromEntity</code> to return. For this reason functions which construct a <code>Store</code> must be explicitly typed, like <code>gameStore</code> below, as otherwise no more specific type than <code>Store a</code> can be inferred.</p>

<p>So the instance for a game of hangman is:</p>

<pre><code>data public Game = 
    private Game word :: String guesses :: String deriving Show, Inputable, Outputable;

gameStore :: Store Game;
public gameStore = Store "Org.Kablambda.AppEngine.Test.Game" ["word","guesses"];

instance Storeable Game where
    store = gameStoreA;
    ;

private gameStoreA a = gameStore;
</code></pre>

<p>The public <code>gameStore</code> function is used when we wish to query.</p>

<h3>Converting between CAL values and AppEngine Entities</h3>

<p>Two conversion functions are used, one in each direction. In both cases the bulk of the work is carried out in Java functions.</p>

<h4>From a CAL value to an Entity</h4>

<pre><code>toEntity :: Storeable a =&gt; a -&gt; Entity;
public toEntity !r =
    jObjectToEntity (store r).Store.kind (outputList $ (store r).Store.fields) (output r);
</code></pre>

<p>where:</p>

<pre><code>foreign unsafe import jvm "static method org...jObjectToEntity" 
    public jObjectToEntity :: String -&gt; JList -&gt; JObject -&gt; Entity;
</code></pre>

<p>The parameters passed to <code>jObjectToEntity</code> are the kind of entity to create, the list of names to use for the fields of the CAL value, and the CAL value, converted to a <code>JObject</code> by the <code>output</code> function. <code>Storeable</code> instances should all derive <code>Outputable</code>, so <code>output r</code> uses the default implementation of <code>output</code> to convert the algebraic data type instance to an instance of the CAL Java support class <code>AlgebraicValue</code>. The fields are transferred to the AppEngine entity like this:</p>

<pre><code>Entity entity = new Entity(kind);
AlgebraicValue av = ...;
entity.setProperty(DC_NAME, av.getDataConstructorName());
entity.setProperty(DC_ORDINAL, av.getDataConstructorOrdinal());
for (String fieldName : fieldNames) {
    entity.setProperty(fieldName, av.getNthArgument(i++));
}
</code></pre>

<h4>From an Entity to a CAL value</h4>

<pre><code>fromEntity :: Storeable a =&gt; Store a -&gt; Entity -&gt; a;
public fromEntity !s !e =
    input $ jEntityToJObject (outputList s.Store.fields) e;
</code></pre>

<p>where:</p>

<pre><code>foreign unsafe import jvm "static method org...entityToJObject" 
   public jEntityToJObject :: JList -&gt; Entity -&gt; JObject;
</code></pre>

<p><code>jEntityToJObject</code> reverses the process, creating an <code>AlgebraicValue</code> which is converted to a CAL value by the <code>input</code> function.</p>

<h3>The Data Store Monad</h3>

<p>Because data store operations operate via side effects we need to create a <code>Monad</code> instance to manage them. This is required or two reasons:</p>

<ul>
<li><p>We need to ensure that our data store operations happen in a definite sequence &#8212; our puts must happen before we commit the transaction, for example. Lazy evaluation won&#8217;t guarantee this without special attention.</p></li>
<li><p>Some operation don&#8217;t produce results, or produce results which will be ignored, so lazy evaluation won&#8217;t cause these operations to happen at all.</p></li>
</ul>

<p>We define the following functions for use with our <code>Monad</code> (the type of which is <code>DSM</code>):</p>

<pre><code>put :: Storeable a =&gt; a -&gt; DSM Key;
</code></pre>

<p>The <code>put</code> function creates a new record, returning the <code>Key</code> it was assigned by the data store.</p>

<pre><code>update :: Storeable a =&gt; Entity -&gt; a -&gt; DSM Key;
</code></pre>

<p>The <code>update</code> function replaces a previously retrieved entity with a new value, returning the <code>Key</code> (which will always be the same as the old key). Note that the original Entity is used only for the value of its key &#8212; all the replacement fields come from the new <code>Storeable</code> value.</p>

<pre><code>delete :: Entity -&gt; DSM ();
</code></pre>

<p>The <code>delete</code> function deletes a previously retrieved entity.</p>

<pre><code>find :: (Storeable a) =&gt; Store a -&gt; Key -&gt; DSM (Maybe (Entity,a));
</code></pre>

<p>The <code>find</code> function looks for a record using a <code>Key</code> and returns it or <code>Nothing</code> if it does not exist. The return value consists of a pair of values: the raw <code>Entity</code> and its value when converted to a <code>Storeable</code> instance. This allows update to be used later. An alternative design would have been to require <code>Storeable</code> instances to be able to store a key, but I think the current design better separates the concerns of data storage from the domain objects.</p>

<pre><code>query :: (Storeable a, Outputable b) =&gt; Store a -&gt; [(String,FilterOperator,b)] -&gt; [(String,SortDirection)] -&gt; DSM [(Entity,a)];
</code></pre>

<p>The <code>query</code> function returns a sorted list of (Entity,Storeable) pairs, based on a list of filter criteria applied to attributes of the records.</p>

<pre><code>commit :: DSM ();
</code></pre>

<p>The <code>runDSM</code> function described below starts and commits the transaction within which the monad is being run, but if you need to operate on entities from more than one entity group you must commit the original transaction and start a new one using the <code>commit</code> function.</p>

<p>These functions are combined with the normal monad operators of <code>bind</code> and <code>anonymousBind</code>, and then the resulting function is &#8216;run&#8217; with <code>runDSM</code>:</p>

<pre><code>runDSM :: DSM a -&gt; a;
</code></pre>

<h3>Key Conversion</h3>

<p>In the context of a web application we may wish to store keys in cookies or generated URLs. The following functions are provided for extracting <code>Key</code>s from <code>Entity</code> instances, and converting <code>Key</code>s to and from strings.</p>

<pre><code>public keyToString :: Key -&gt; String; 
public stringToKey :: String -&gt; Key;
public getKey :: Entity -&gt; Key;
</code></pre>

<h2>Example</h2>

<p>Suppose we want to retrieve a <code>Game</code>, add a letter to the set of guesses and store it again:</p>

<pre><code>    updateGame :: Key -&gt; Char -&gt; Key;
    updateGame key letter =
        runDSM (find gameStore key `bind` (\p -&gt;
            let (entity, game) = fromJust p;
            in update entity (addGuess letter game)
        ));
</code></pre>

<p>where <code>addGuess</code> returns a new game with the given letter added to its set of guesses. This function will terminate with an error if the <code>Game</code> is not found, that is, if <code>find</code> returns <code>Nothing</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/05/12/cal-hangman-on-gae-part-2-the-datastore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CAL Hangman on Google AppEngine, Part 1</title>
		<link>http://www.kablambda.org/blog/2009/04/27/cal-hangman-on-google-appengine-part-1/</link>
		<comments>http://www.kablambda.org/blog/2009/04/27/cal-hangman-on-google-appengine-part-1/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 08:55:46 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[CAL and Open Quark]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=78</guid>
		<description><![CDATA[This post describes a simple implementation of the game &#8216;Hangman&#8217;, written in CAL for Google Appengine.

Introduction

Hangman is a simple word guessing game &#8212; the computer chooses a word, telling you only how many letters it has. You that it contains a particular letter. Correct guesses fill in those letters in the word, until you have [...]]]></description>
			<content:encoded><![CDATA[<p>This post describes a simple implementation of the game &#8216;Hangman&#8217;, written in <a href="http://openquark.org">CAL</a> for <a href="http://code.google.com/appengine">Google Appengine</a>.</p>

<h2>Introduction</h2>

<p>Hangman is a simple word guessing game &#8212; the computer chooses a word, telling you only how many letters it has. You that it contains a particular letter. Correct guesses fill in those letters in the word, until you have guessed all the letters in the word, or you  make too many incorrect guesses and lose.</p>

<p>You can try my <a href="http://aet-tgdavies.appspot.com/hangman/play">Hangman for AppEngine</a> implementation to understand the game. The source is available at <a href="https://code.launchpad.net/cal-on-gae">launchpad</a>.</p>

<p>Hangman is a very simple game &#8212; the state is just the word being guessed, and the letters guessed so far. The point of implementing it in CAL on AppEngine is to develop CAL modules for the AppEngine API classes.</p>

<h2>Design</h2>

<p>It would be easy to implement hangman as a mostly client-side browser based application, but that wouldn&#8217;t have exercised much of the AppEngine API.</p>

<p>To make the task interesting, I decided that the game state would be persisted on the server, and a user&#8217;s current game would be identified by a cookie in their browser. So you can make some guesses, close your browser, and come back to the same game later.</p>

<h2>Http Module</h2>

<p>The <code>Http</code> module provides function for creating a server which handles requests and creates responses. The source is <a href="http://bazaar.launchpad.net/%7Etgdavies/cal-on-gae/main/annotate/head%3A/src/CAL/Org/Kablambda/AppEngine/Http.cal">here</a>.</p>

<h3>The Server Function</h3>

<p>All requests go through a single servlet, which is configured with <code>init-param</code>s to reflectively call a static method generated by the CAL stand-alone jar builder.</p>

<p>The function called by the servlet must have the type <code>HttpServletRequest -&gt; JHttpServletResponse</code>. These CAL types are simply imports of the Java <code>HttpServletRequest</code> and <code>HttpServletResponse</code> classes.</p>

<pre><code>data foreign unsafe import jvm "javax.servlet.http.HttpServletRequest"
    public HttpServletRequest deriving Inputable, Outputable;

data foreign unsafe import jvm "javax.servlet.http.HttpServletResponse"
    private JHttpServletResponse deriving Inputable, Outputable;
</code></pre>

<p><code>JHttpServletResponse</code> is private to the module because it is mutable and so shouldn&#8217;t be exposed to clients of the module. Instead <code>Http</code> provides a data type <code>HttpServletResponse</code>:</p>

<pre><code>data public HttpServletResponse =
    private HttpServletResponse cookies :: [Cookie] headers :: [Header] body :: HttpServletResponseBody;

data public HttpServletResponseBody =
    private Ok contentType :: String content :: (Array Byte) |
    private Error code :: Int message :: (Maybe String) |
    private Redirect url :: String;
</code></pre>

<p>This allows the client to assemble the state of a response, which is then applied to the response in a single operation by the <code>Http</code> module. A monad to sequence operations on the Java response object would have been another alternative, but that wouldn&#8217;t enforce correct construction of the response to the same degree &#8212; e.g. the client might not set a content type. Note that the actual constructors are private so that the structure of the type is not exposed to clients of this module.</p>

<p>The current data type doesn&#8217;t allow the response to be streamed.</p>

<p>As clients can&#8217;t see or use <code>JHttpServletResponse</code> they need to use the <code>server</code> function to create a web server:</p>

<pre><code>server :: [HttpServletRequest -&gt; Maybe HttpServletResponse] -&gt; HttpServletRequest -&gt; JHttpServletResponse -&gt; ();
</code></pre>

<p>This function takes a list of handlers, each of which is tried in sequence until one returns a response. So the server function for the hangman web application is:</p>

<pre><code>public service =
    server [currentGameHandler, newGameHandler, guessHandler, restartHandler];
</code></pre>

<h3>Writing Handlers</h3>

<p>The <code>Http</code> module provides functions to test and retrieve properties of the request, and combinators to build handlers from these individual functions. The combinators are inspired by Mark Tullsen&#8217;s <em>First Class Patterns</em>.</p>

<p>Each combinator combines two functions, each of which extracts a property of the request, and returns a function of the type <code>HttpServletRequest -&gt; Maybe a</code>.</p>

<p>It isn&#8217;t clear to me that this is the very best approach &#8212; experimenting with a <code>Maybe/Reader</code> monad stack would be interesting.</p>

<h4>Combinators</h4>

<pre><code>hOr :: (HttpServletRequest -&gt; Maybe a) -&gt; (HttpServletRequest -&gt; Maybe a) -&gt; (HttpServletRequest -&gt; Maybe a);
</code></pre>

<p><code>hOr</code> requires that at least one of two extraction functions succeeds, i.e. returns <code>Just x</code>. The final result is the result of the first extraction function to succeed (if the first extraction function succeeds, the second is not evaluated).</p>

<pre><code>hThen :: (HttpServletRequest -&gt; Maybe a) -&gt; (HttpServletRequest -&gt; Maybe b) -&gt; (HttpServletRequest -&gt; Maybe b);
</code></pre>

<p><code>hThen</code> requires that both the extraction functions succeed, but it discards the result of the first extraction function.</p>

<pre><code>hAnd :: (HttpServletRequest -&gt; Maybe a) -&gt; (HttpServletRequest -&gt; Maybe b) -&gt; (HttpServletRequest -&gt; Maybe (a,b));
</code></pre>

<p><code>hAnd</code> requires that both extraction functions succeed, and returns their results as a pair.</p>

<pre><code>hNot :: (HttpServletRequest -&gt; Maybe a) -&gt; (HttpServletRequest -&gt; Maybe ());
</code></pre>

<p><code>hNot</code> reverses the sense of an extractor, succeeding if it fails and vice-versa.</p>

<p>The following combinators have specialised functions, rather than acting to combine two extraction functions.</p>

<pre><code>hCompose :: (HttpServletRequest -&gt; Maybe a) -&gt; (a -&gt; b) -&gt; (HttpServletRequest -&gt; Maybe b);
</code></pre>

<p><code>hCompose</code> transforms the result of an extraction function.</p>

<pre><code>hApply :: (HttpServletRequest -&gt; Maybe a) -&gt; (a -&gt; HttpServletResponse) -&gt; (HttpServletRequest -&gt; Maybe HttpServletResponse);
</code></pre>

<p><code>hApply</code> combines a sequence of extraction functions with a function that produces a response.</p>

<pre><code>hAttempt :: (HttpServletRequest -&gt; Maybe a) -&gt; (a -&gt; Maybe HttpServletResponse) -&gt; (HttpServletRequest -&gt; Maybe HttpServletResponse);
</code></pre>

<p><code>hAttempt</code> is like <code>hApply</code>, but the response generation function returns <code>Maybe HttpServletResponse</code>, allowing further conditional processing outside the context of combined extraction functions.</p>

<h4>Request Attribute Extractors</h4>

<p>These functions look at attributes of the response and return their values (which may amount to just signalling their presence or absence).</p>

<pre><code>getParameter :: String -&gt; HttpServletRequest -&gt; Maybe (Maybe String);
</code></pre>

<p><code>getParameter</code> extracts the value of a named parameter from the request. It always succeeds, returning <code>Just Nothing</code> or <code>Just $ Just paramValue</code>.</p>

<pre><code>requireParameter :: String -&gt; HttpServletRequest -&gt; Maybe String;
</code></pre>

<p><code>requireParameter</code> extracts the value of a named parameter, but fails (i.e. returns <code>Nothing</code>) if it is not set.</p>

<p>There are similar <code>get/require</code> <code>Header/Cookie</code> functions.</p>

<pre><code>matchUrl :: String -&gt; HttpServletRequest -&gt; Maybe ();
</code></pre>

<p><code>matchUrl</code> takes a string containing a regular expression, and succeeds if the regular expression matches the path info of the request. It would be useful to have another function which returns the values of capturing groups of the regular expression.</p>

<h3>Creating the Response</h3>

<p>Utility functions are provided for each common response type.</p>

<pre><code>ok :: HasByteRep a =&gt; String -&gt; a -&gt; HttpServletResponse;
public ok contentType content = ...

textHtml :: HasByteRep a =&gt; a -&gt; HttpServletResponse;
public textHtml = ok "text/html";

redirect :: String -&gt; HttpServletResponse;
public redirect url = ...

err :: Int -&gt; Maybe String -&gt; HttpServletResponse;
public err code msg = ...
</code></pre>

<p>These functions all create requests with default headers. Headers and Cookies are added by applying a function to the request.</p>

<pre><code>addHeader :: Header -&gt; HttpServletResponse -&gt; HttpServletResponse;
addCookie :: Cookie -&gt; HttpServletResponse -&gt; HttpServletResponse;  
</code></pre>

<h2>Example</h2>

<p>Rather than an example from the hangman game, here&#8217;s a simple example which uses the functions discussed directly.</p>

<pre><code>helloHandler =
    let
        page p = 
            let (firstName, maybeLastName) = p;
            in ok "text/plain" (
                case maybeLastName of
                    Just lastName -&gt; "Greetings, " ++ firstName ++ " " ++ lastName;
                    Nothing -&gt; "Hi there " ++ firstName;
                );
    in
        matchUrl "/hello" `hThen`
        (requireParameter "firstName") `hAnd`
        (getParameter "lastName") `hApply` page;
</code></pre>

<p>This handler will return a page for the url <code>/hangman/hello</code> <em>if</em> the <code>firstName</code> parameter is present. To keep the example as simple as possible it uses the <code>text/plain</code> content type to avoid the verbiage of an HTML page.</p>

<h2>To be continued&#8230;</h2>

<p>In the next instalment I&#8217;ll describe the CAL module which supports the AppEngine datastore.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/04/27/cal-hangman-on-google-appengine-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Functional Programming on Google AppEngine</title>
		<link>http://www.kablambda.org/blog/2009/04/09/functional-programming-on-google-appengine/</link>
		<comments>http://www.kablambda.org/blog/2009/04/09/functional-programming-on-google-appengine/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 08:17:33 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[CAL and Open Quark]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=72</guid>
		<description><![CDATA[I&#8217;ve always hoped that Java would be the next Google App Engine language. Google have provided a solid platform with a &#8216;real&#8217; JVM and few restrictions.

I deployed the sample application created with the Eclipse plugins a few minutes after my account was upgraded to support Java, and then I went on to deploy an application [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always hoped that Java would be the next Google App Engine language. Google have provided a solid platform with a &#8216;real&#8217; JVM and few restrictions.</p>

<p>I deployed the sample application created with the Eclipse plugins a few minutes after my account was upgraded to support Java, and then I went on to deploy an application written in <a href="http://openquark.org">CAL</a>.</p>

<p>There are two ways of integrating CAL and Java. The first is to dynamically load and compile a workspace at run time, and then reflectively call functions in the workspace&#8217;s modules. I&#8217;ve used this approach in the past, for example for <a href="http://www.kablambda.org/blog/2008/03/27/a-cal-webapp-with-persistent-data-using-gwt-stm-and-bdb/">CAL/GWT integration</a>.</p>

<p>There are two reasons not to use this approach for an AppEngine application. Firstly, when CAL loads a workspace it uses a SecurityManager, which GAE doesn&#8217;t allow. It&#8217;s just used to get the class of the caller of a function so the code could probably be replaced by looking at the stack trace of an un-thrown Exception, but that would involve a custom CAL build. I suspect that this approach would also want to create some local files, which also wouldn&#8217;t work on AppEngine.</p>

<p>The other reason not to use this approach is that AppEngine runs your application on (potentially) many different JVM instances, and may stop your application when it is idle and restart it when it receives a request. Nothing I&#8217;ve read so far indicates how often this happens, but start up overhead which would be perfectly acceptable in a normal application server is likely to be a bad idea in AppEngine.</p>

<p>CAL modules can also be compiled statically to a &#8217;stand-alone&#8217; jar file.</p>

<p>Each public function in the module becomes a static function on the resulting class, e.g.:</p>

<pre><code>square :: Int -&gt; Int;
public square n = n * n;
</code></pre>

<p>becomes:</p>

<pre><code>public static int square(int n, ExecutionContext context)
</code></pre>

<p>If we hadn&#8217;t explicitly typed square, it would have the inferred type <code>Num a =&gt; a -&gt; a</code> and the function would have the signature</p>

<pre><code>public static CalValue square(CalValue n, ExecutionContext context);
</code></pre>

<p>Where a <code>CalValue</code> can hold any Java types which CAL knows how to convert to CAL types via the <code>input</code> function, and <code>ExecutionContext</code> really just caches <a href="http://haskell.org/haskellwiki/Constant_applicative_form">Constant Applicative Forms</a>.</p>

<p>So the components of a minimal CAL application for AppEngine are:</p>

<ol>
<li>A module which imports <code>HttpServletRequest</code> and <code>HttpServletResponse</code> and provides suitable functions to get their properties and to set attributes of the response.</li>
<li>A function with the type <code>HttpServletRequest -&gt; HttpServletResponse -&gt; ()</code>.</li>
<li>A servlet which calls that function.</li>
<li>Extensions to the example <code>build.xml</code> provided by Google which package up the CAL modules into a stand-alone jar, and include the runtime support jars CAL needs.</li>
</ol>

<p>Additionally all the other AppEngine Services (Data Store, Cache, Mail etc.) need to be made available to CAL (in Monads of course <img src='http://www.kablambda.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ), but that can be done piecemeal as you need them.</p>

<p>I&#8217;ll just give one example from the Http module, as it illustrates the issue of dealing with <code>null</code> being returned by Java methods.</p>

<p>First I import the <code>HttpServletRequest.getParameter</code> method:</p>

<pre><code>foreign unsafe import jvm "method getParameter"
    jGetParameter :: HttpServletRequest -&gt; String -&gt; String;
</code></pre>

<p>But it isn&#8217;t made public. The &#8216;real&#8217; getParameter function is defined like this:</p>

<pre><code>public getParameter req s =
    let v = jGetParameter req s;
    in if isNullString v then Nothing else Just v;
</code></pre>

<p>Allowing the <code>Maybe</code> type to handle the possibility that a parameter may not be set.</p>

<p>The <code>build.xml</code> changes are:</p>

<pre><code>&lt;target name="copy-quark-jars"&gt;
    &lt;copy
            todir="war/WEB-INF/lib"
            flatten="true"&gt;
          &lt;fileset dir="${quark.dir}/Quark/bin/java/release"&gt;
            &lt;include name="**/calLibraries.jar" /&gt;
            &lt;include name="**/calPlatform.jar" /&gt; &lt;!-- maybe don't need? --&gt;
            &lt;include name="**/calRuntime.jar" /&gt;
            &lt;include name="**/calUtilities.jar" /&gt;
          &lt;/fileset&gt;
          &lt;fileset dir="${quark.dir}/Quark/lib/Resources/External/java/"&gt;
            &lt;include name="**/icu4j.jar" /&gt;
            &lt;include name="**/log4j.jar" /&gt;
          &lt;/fileset&gt;
        &lt;/copy&gt;
&lt;/target&gt;

&lt;target name="build-quark-standalone" depends="copyjars"&gt;
    &lt;exec executable="quarkc.sh"&gt;
        &lt;arg value="workspace.cws"/&gt;
        &lt;arg value="-lib"/&gt;
        &lt;arg value="${moduleName}"/&gt;
        &lt;arg value="public"/&gt;
        &lt;arg value="${className}"/&gt;
        &lt;arg value="war/WEB-INF/lib/calmodule.jar"/&gt;
        &lt;env key="QUARK_CP" value="src:war/WEB-INF/lib/appengine-api-1.0-sdk-1.2.0.jar:${sdk.dir}/lib/shared/geronimo-servlet_2.5_spec-1.2.jar"/&gt;
    &lt;/exec&gt;
&lt;/target&gt;
</code></pre>

<p>Now to do something useful with it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/04/09/functional-programming-on-google-appengine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Computer Scientists as an ethical elite</title>
		<link>http://www.kablambda.org/blog/2009/02/13/computer-scientists-as-an-ethical-elite/</link>
		<comments>http://www.kablambda.org/blog/2009/02/13/computer-scientists-as-an-ethical-elite/#comments</comments>
		<pubDate>Fri, 13 Feb 2009 03:33:08 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://www.kablambda.org/blog/?p=59</guid>
		<description><![CDATA[
&#8230; every culture &#8230; needs a kind of self-questioning, ethical elite &#8230;
Perhaps you see very little link between the Charles of 1267 with all his newfangled French notions of chastity and chasing after Holy Grails, the Charles of 1867 with his loathing of trade and the Charles of today, a computer scientist deaf to the [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
&#8230; every culture &#8230; needs a kind of self-questioning, ethical elite &#8230;
Perhaps you see very little link between the Charles of 1267 with all his newfangled French notions of chastity and chasing after Holy Grails, the Charles of 1867 with his loathing of trade and the Charles of today, a computer scientist deaf to the screams of the tender humanists who begin to discern their own redundancy. But there is a link: they all rejected or reject the notion of <i>possession</i> as the purpose of life, whether it be of a woman&#8217;s body, or of high profit at all costs, or of the right to dictate the speed of progress. The scientist is but one more form; and will be superceded.
</blockquote>

<p>John Fowles, <i>The French Lieutenant&#8217;s Woman</i>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/02/13/computer-scientists-as-an-ethical-elite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>bash command completion for jstack/jps</title>
		<link>http://www.kablambda.org/blog/2009/01/27/bash-command-completion-for-jstackjps/</link>
		<comments>http://www.kablambda.org/blog/2009/01/27/bash-command-completion-for-jstackjps/#comments</comments>
		<pubDate>Tue, 27 Jan 2009 11:24:40 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=56</guid>
		<description><![CDATA[I&#8217;ve only recently become aware of jps and jstack, Sun&#8217;s tools for listing Java processes and for producing a thread dump from them. They beat the old ps &#124; fgrep java and kill -3 (and then try to find the log file your thread dump went into&#8230;).

You still have to use jps, copy the appropriate [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve only recently become aware of <a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jps.html">jps</a> and <a href="http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html">jstack</a>, Sun&#8217;s tools for listing Java processes and for producing a thread dump from them. They beat the old <code>ps | fgrep java</code> and <code>kill -3</code> (and then try to find the log file your thread dump went into&#8230;).</p>

<p>You still have to use <code>jps</code>, copy the appropriate pid and then paste it into your jstack command line, which is inconvenient. I decided to implement <code>bash</code> command completion for the pid argument.</p>

<p>Of course that isn&#8217;t useful by itself &#8212; seeing a list of available JVM pids tells you nothing about which one you want, so I arranged for each pid to be accompanied by the full package name for the application&#8217;s main class or the full path name to the application&#8217;s JAR file, as provided by <code>jsp -l</code>.</p>

<p>The trick is to give <code>compgen</code> the list of options in the form <code>&lt;pid&gt;#&lt;description&gt;</code>, as it splits the list of options on whitespace, but then to modify the array of options so that each is <code>&lt;pid&gt; #&lt;description&gt;</code> so that the description is interpreted as a comment by <code>bash</code> in the final command line:</p>

<pre><code>_jstack()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    opts=`jps -l | fgrep -v sun.tools.jps.Jps | sed -e's/ /#/' | tr '\n' ' '`
    replies=( $(compgen -W "${opts}" -- ${cur}) )
    for (( i = 0 ; i &lt; ${#replies[@]} ; i++ ))
    do
    COMPREPLY[$i]=`echo ${replies[$i]} | sed -e's/#/ #/'`
    done
    return 0
}
complete -F _jstack jstack
</code></pre>

<p>The code above can be put in your <code>.bashrc</code> file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2009/01/27/bash-command-completion-for-jstackjps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Books from India Update</title>
		<link>http://www.kablambda.org/blog/2008/10/01/books-from-india-update/</link>
		<comments>http://www.kablambda.org/blog/2008/10/01/books-from-india-update/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 03:19:49 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=52</guid>
		<description><![CDATA[I received the &#8216;Eastern Economy Edition&#8217; of &#8220;Advanced Topics in Types and Programming Languages&#8221; last week.

It&#8217;s a well constructed hardcover.

The negative points are:
- It has an &#8216;inky&#8217; smell.
- The paper is thinner than usual, so you can see the printing on the other side of the page.

Neither is a real problem.
]]></description>
			<content:encoded><![CDATA[<p>I received the &#8216;Eastern Economy Edition&#8217; of &#8220;Advanced Topics in Types and Programming Languages&#8221; last week.</p>

<p>It&#8217;s a well constructed hardcover.</p>

<p>The negative points are:
- It has an &#8216;inky&#8217; smell.
- The paper is thinner than usual, so you can see the printing on the other side of the page.</p>

<p>Neither is a real problem.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2008/10/01/books-from-india-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Laptop design stupidity</title>
		<link>http://www.kablambda.org/blog/2008/08/03/laptop-design-stupidity/</link>
		<comments>http://www.kablambda.org/blog/2008/08/03/laptop-design-stupidity/#comments</comments>
		<pubDate>Sun, 03 Aug 2008 10:28:16 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[General Interest]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=47</guid>
		<description><![CDATA[A relative of mine has a recent HP Pavillion laptop. (I suggested that she get a Mac, but she was concerned about MS Office compatibility).

I was doing some telephone support trying to reattach it to her wireless network tonight. I was ultimately unsuccessful, but I did learn two reasons why HP laptops suck.


HP has their [...]]]></description>
			<content:encoded><![CDATA[<p>A relative of mine has a recent HP Pavillion laptop. (I suggested that she get a Mac, but she was concerned about MS Office compatibility).</p>

<p>I was doing some telephone support trying to reattach it to her wireless network tonight. I was ultimately unsuccessful, but I did learn two reasons why HP laptops suck.</p>

<ol>
<li>HP has their own &#8216;wireless assistant&#8217; wizard, with a plethora of confusing options, so even my limited knowledge of Windows network configuration was useless.</li>
<li>The laptop has a wireless on/off switch on its front. This switch was in the off position, but the software couldn&#8217;t tell that. All it could say was &#8216;please check the network switch&#8217; &#8212; and it didn&#8217;t show a picture giving the switch&#8217;s location. I had to Google and then describe the location over the phone. It&#8217;s a hardware switch when it should be a software switch, and to add insult to injury, its state isn&#8217;t even visible to the software!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2008/08/03/laptop-design-stupidity/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ICFP2008 Programming Contest</title>
		<link>http://www.kablambda.org/blog/2008/07/16/icfp2008-programming-contest/</link>
		<comments>http://www.kablambda.org/blog/2008/07/16/icfp2008-programming-contest/#comments</comments>
		<pubDate>Wed, 16 Jul 2008 05:31:39 +0000</pubDate>
		<dc:creator>Tom Davies</dc:creator>
				<category><![CDATA[Computer Science]]></category>

		<guid isPermaLink="false">http://diversions.nfshost.com/blog/?p=43</guid>
		<description><![CDATA[Along with some colleagues I entered the ICFP programming contest this year.

You can read some more about our experience at Matt&#8217;s blog.

I thought the problem &#8212; guiding a Mars rover to a goal amongst obstacles &#8212; was very well chosen. It was possible to navigate the example maps with very simple software, so everyone could [...]]]></description>
			<content:encoded><![CDATA[<p>Along with some colleagues I entered the <a href="http://icfpcontest.org/">ICFP programming contest</a> this year.</p>

<p>You can read some more about our experience at <a href="http://www.mattryall.net/blog/2008/07/icfp-programming-contest-2008">Matt&#8217;s blog</a>.</p>

<p>I thought the problem &#8212; guiding a Mars rover to a goal amongst obstacles &#8212; was very well chosen. It was possible to navigate the example maps with very simple software, so everyone could get the satisfaction of seeing their rover succeed. If you had the time and skills, there were a vast number of directions to go in to improve your rover&#8217;s performance. This compares favourably with last year&#8217;s problem. <a href="http://save-endo.cs.uu.nl/">That problem</a> was very clever, and I had a lot of fun playing with it, but I never got close to having a worthwhile submission because the threshold for even partial success was quite high. So kudos to the ICFP2008 team for creating a problem which has a low barrier to entry while still having the &#8216;dynamic range&#8217; needed to challenge the top teams.</p>

<p>I&#8217;ll definitely participate next year. Among the lessons we learnt:</p>

<ul>
<li>Have all the team on the same premises, especially for the first few hours. When you are writing software this quickly you need to all be on the same page all the time.</li>
<li>For developing geometry based heuristics visualisation is very important. You need to be able to see what your code is trying to do &#8212; where it is trying to go, what it thinks is blocking it, when it starts to turn and so on.</li>
</ul>

<p>We wrote our entry in Java, but over the next few weeks I plan to produce something just as sophisticated in <a href="http://openquark.org">CAL</a>. It is a <em>functional</em> programming contest after all <img src='http://www.kablambda.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.kablambda.org/blog/2008/07/16/icfp2008-programming-contest/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
