<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>programming &middot; Arguable Intelligence</title><link>https://ojmason.net/tags/programming/</link><description>Personal musings on computational linguistics, AI, sailing, and generated fiction.</description><language>en-gb</language><managingEditor>Oliver Mason</managingEditor><webMaster>Oliver Mason</webMaster><lastBuildDate>Thu, 04 Nov 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://ojmason.net/tags/programming/index.xml" rel="self" type="application/rss+xml"/><item><title>Stockholm Syndrome</title><link>https://ojmason.net/stockholm-syndrome/</link><guid isPermaLink="true">https://ojmason.net/stockholm-syndrome/</guid><pubDate>Thu, 04 Nov 2021 00:00:00 +0000</pubDate><category>programming</category><category>php</category><category>nanogenmo</category><description>I&rsquo;m starting a new temporary project, NaNoGenMo (again). Here I attempt to write a program that generates a 50k word novel during the month of November, because NaNoWriMo (where you just write the novel) would be too easy. As always with any software project that doesn&rsquo;t have any constraints, there is a choice of language in which to implement it. Sensible languages for such a project would be Lisp or Scheme, as it is AI related, and these languages are well-suited to it. (Note: a lot of so-called AI is nowadays done in Python; but that is mainly machine learning, which isn&rsquo;t really AI in the sense that I understand it. Also, I haven&rsquo;t really done any serious Python development, so maybe not this time).</description><content:encoded><![CDATA[<p>I&rsquo;m starting a new temporary project, NaNoGenMo (again). Here I attempt to write a program that generates a 50k word
novel during the month of November, because NaNoWriMo (where you just write the novel) would be too easy. As always with
any software project that doesn&rsquo;t have any constraints, there is a choice of language in which to implement it. Sensible
languages for such a project would be Lisp or Scheme, as it is AI related, and these languages are well-suited to it.
(Note: a lot of so-called AI is nowadays done in Python; but that is mainly machine learning, which isn&rsquo;t really AI in the
sense that I understand it. Also, I haven&rsquo;t really done any serious Python development, so maybe not this time).</p>
<p>However, I have decided to use <a href="https://en.wikipedia.org/wiki/PHP">PHP</a>.</p>
<p>This is a somewhat surprising choice (even surprising to myself), as I don&rsquo;t like PHP. It&rsquo;s a hacky language, which is horrendous.
But recently I have done some work in it for the sailing club, where our results are calculated with it, and I got used to it.
For all its faults, it has a good library, and is fairly flexible. You can even write programs in a kind of functional style.
And it&rsquo;s ubiquitous on the web, so if I ever want to run my system (or parts of it) on the web, I should have no problems doing so.</p>
<p>You can run it pretty easily (just with <code>php YOUR-FILE</code>), so you don&rsquo;t need to worry about build files or class paths or other
complicated stuff. And it&rsquo;s portable.</p>
<p>In a way it&rsquo;s a very simple and straightforward language, so I can pretty much focus on <em>what</em> I want to do, and don&rsquo;t need to worry about
the <em>how</em>. I&rsquo;ll see how it goes, but so far I&rsquo;m quite happy with it. Especially since I realised how to call any function based on its name,
which means I re-invented some kind of object system&hellip; if an object (a plain array) has a key &ldquo;fn_print&rdquo;, then that is used to print itself.
Very easy and nifty. Similarly I can compose function names from some other values, and then call a function. I can even check if it exists,
and fall back to a default if not.</p>
<p>Yes, with other languages you get that kind of thing for free, but sometimes it is easiest to take what&rsquo;s in front of you. I have
railed against PHP in the past, and it&rsquo;s not a good language, but it&rsquo;s there, it&rsquo;s everywhere, and it&rsquo;s easy to use. So let&rsquo;s see how
I get on with a larger project!</p>
]]></content:encoded></item><item><title>Solving Combinatory Problems with Erlang</title><link>https://ojmason.net/solving-combinatory-problems-with-erlang/</link><guid isPermaLink="true">https://ojmason.net/solving-combinatory-problems-with-erlang/</guid><pubDate>Sun, 10 May 2015 00:00:00 +0000</pubDate><category>programming</category><category>erlang</category><description>My daughter had some maths homework the other day:
You have 4 bags, each full of the numbers 1, 3, 5, and 7 respectively. Take 10 of the numbers that when added up make 37. What numbers are they?
So far so good: that sounds easy enough. But a bit of trial and error quickly leads nowhere. Something can’t be right. So, let’s get the computer to work it out.</description><content:encoded><![CDATA[<p>My daughter had some maths homework the other day:</p>
<blockquote>
<p>You have 4 bags, each full of the numbers 1, 3, 5, and 7 respectively.
Take 10 of the numbers that when added up make 37. What numbers are they?</p>
</blockquote>
<p>So far so good: that sounds easy enough. But a bit of trial and
error quickly leads nowhere. Something can’t be right. So, let’s
get the computer to work it out.</p>
<p>As I haven’t done much Erlang recently I thought I’d give it a go.
And, during a casual glance at Armstrong’s <em>Programming in Erlang</em> I
thought I’d finally understood list comprehensions, so I wrote the
following program:</p>
<pre tabindex="0"><code>-module(comb).
-export([result/0]).
result() -&gt;
[{A+B+C+D+E+F+G+H+I+J,A,B,C,D,E,F,G,H,I,J}||
A &lt;- [1,3,5,7],
B &lt;- [1,3,5,7],
C &lt;- [1,3,5,7],
D &lt;- [1,3,5,7],
E &lt;- [1,3,5,7],
F &lt;- [1,3,5,7],
G &lt;- [1,3,5,7],
H &lt;- [1,3,5,7],
I &lt;- [1,3,5,7],
J &lt;- [1,3,5,7],
A+B+C+D+E+F+G+H+I+J =:= 37].
</code></pre><p>I declare a module with one function, <code>result/0</code>. This finds me ten
variables that can take any of the four specified values and add
up to 37. Simples!</p>
<p>The list comprehension has ten generators, and one filter; it will
return a tuple with the sum and the individual variables’ values.</p>
<pre tabindex="0"><code>Erlang R16B01 (erts-5.10.2) [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.2 (abort with ^G)
1&gt; comb:result().
[]
2&gt;
</code></pre><p>WTF???! An empty list?! So I try changing the 37 to another value, like 36.</p>
<pre tabindex="0"><code>3&gt; comb:result().
[{36,1,1,1,1,1,3,7,7,7,7},
{36,1,1,1,1,1,5,5,7,7,7},
{36,1,1,1,1,1,5,7,5,7,7},
{36,1,1,1,1,1,5,7,7,5,7},
{36,1,1,1,1,1,5,7,7,7,5},
[etc, etc].
</code></pre><p>So it does work! Only, there doesn’t seem to be an answer to the
question. And with a bit of logical reasoning it is obvious: when
adding two odd numbers, you get an even number. So adding ten odd
numbers also yields an even number, but 37 is odd.</p>
<p>What I learnt from this exercise: thinking about the problem
beforehand can save you time, as there was no need to write a program
at all. But then, I did get to use list comprehensions, and have
learnt how powerful they are. And it neatly shows Erlang’s Prolog
roots as well.</p>
]]></content:encoded></item><item><title>Every Test is Valuable</title><link>https://ojmason.net/every-test-is-valuable/</link><guid isPermaLink="true">https://ojmason.net/every-test-is-valuable/</guid><pubDate>Tue, 17 Jul 2012 00:00:00 +0000</pubDate><category>programming</category><category>testing</category><description>After reading Graham Lee’s Test-Driven iOS Development; (disclaimer: affiliate link) I have (again) adopted a test-driven approach to software developing. Whenever I create a new class I write a bunch of tests exercising the class’ properties. One might question the value of this, because there is not really any reason why those should not work. However, having such a test in place just uncovered an as-yet unnoticed bug I introduced in a project.</description><content:encoded><![CDATA[<p>After reading Graham Lee’s <a href="http://www.amazon.co.uk/gp/product/B007RNK0W6/ref=as_li_ss_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B007RNK0W6&amp;linkCode=as2&amp;tag=phrasysnlp-21">Test-Driven iOS Development</a>; (disclaimer:
affiliate link) I have (again) adopted a test-driven approach to
software developing. Whenever I create a new class I write a bunch
of tests exercising the class’ properties. One might question the
value of this, because there is not really any reason why those
should not work. However, having such a test in place just uncovered
an as-yet unnoticed bug I introduced in a project.</p>
<p>Originally the class property in question was going to be set in
the <code>init</code> method, so I tested for the presence of the property
after creating an instance of the relevant class. Easy pass. Weeks
later I did something (and forgot to run the test suite). Today I
did something else, and this time I did run them. Hey presto, failed
test. And completely unexpected, because it was the property
exercising one. How on Earth did that happen?</p>
<p>Upon closer inspection I tracked it down to a refactoring, where I
extracted some code from <code>init</code> as there were now multiple ways an
object could be initialised. The failing code was part of that, and
I realised that it was called from the new <code>initFromFile:</code> method,
but <em>no longer from the default initialiser</em>. Easy mistake to make.
And had I run my test-suite more consistently, my application would
not have been with a potential bug in the meantime.</p>
<p>What did I take home from this?</p>
<ul>
<li>Even Mickey-Mouse-tests are valuable. No test is too small to be useful
(provided it’s actually testing something valid).</li>
<li>The test-suite should really be run after every change. I’ll have to check
if I can get Xcode to run them automatically after each compilation…</li>
</ul>
<p><em>Update</em>: Since I stopped doing much iOS or Mac OS work, I no longer used Xcode.
And I&rsquo;m not missing it :)</p>
]]></content:encoded></item><item><title>Thinking Erlang, or Creating a Random Matrix without Loops</title><link>https://ojmason.net/thinking-in-erlang-random-matrix-without-loops/</link><guid isPermaLink="true">https://ojmason.net/thinking-in-erlang-random-matrix-without-loops/</guid><pubDate>Thu, 26 Feb 2009 00:00:00 +0000</pubDate><category>programming</category><category>erlang</category><description>For a project, my Erlang implementation of a fast PFNET algorithm, I needed to find a way to create a random matrix of integers (for path weights), with the diagonal being filled with zeroes. I was wondering how best to do that, and started off with two loops, an inner one for each row, and an outer one for the full set of rows. Then the problem was how to tell the inner loop at what position the ‘0’ should be inserted. I was thinking about passing a row-ID, when it suddenly clicked: lists:seq/2 was what I needed! This method, which I previously thought was pretty useless, creates a list with a sequence of numbers (the range is specified in the two parameters). For example,</description><content:encoded><![CDATA[<p>For a project, my <a href="/blog/fast-pfnets-in-erlang/">Erlang implementation of a fast PFNET algorithm</a>,
I needed to find a way to create a random matrix of integers (for
path weights), with the diagonal being filled with zeroes.  I was
wondering how best to do that, and started off with two loops, an
inner one for each row, and an outer one for the full set of rows.
Then the problem was how to tell the inner loop at what position
the ‘0’ should be inserted.  I was thinking about passing a row-ID,
when it suddenly clicked: <code>lists:seq/2</code> was what I needed!  This
method, which I previously thought was pretty useless, creates a
list with a sequence of numbers (the range is specified in the two
parameters).  For example,</p>
<pre tabindex="0"><code>1&gt; lists:seq(1,4).
[1,2,3,4]
2&gt; lists:seq(634,637).    
[634,635,636,637]
3&gt; lists:seq(1000,1003).
[1000,1001,1002,1003]
</code></pre><p>Now I would simply generate a list with a number for each row, and
then send the inner loop off to do its thing, filling the slot given
by the sequence number with a zero, and others with a random value.</p>
<p>But now it gets even better.  Using a separate (tail-)recursive
function for the inner loop didn’t quite seem right, so I thought
a bit more about it and came to the conclusion that this is simply
a mapping; mapping an integer to a list (a vector of numbers, one
of which (given by the integer) is a zero).  So instead of using a
function for filling the row, I call <code>lists:seq/2</code> again and then map
the whole thing.  This is the final version I arrived at, and I’m
sure it can still be improved upon using list comprehensions:</p>
<pre tabindex="0"><code>random_matrix(Size, MaxVal) -&gt;
  random:seed(),
  lists:map(
    fun(X) -&gt;
      lists:map(
          fun(Y) -&gt;
              case Y of 
                 X -&gt; 0; 
                 _ -&gt; random:uniform(MaxVal)
                 end
              end,
          lists:seq(1,Size))
      end,
    lists:seq(1,Size)).
</code></pre><p>This solution seems to be far more idiomatic, and I am beginning
to think that I finally no longer think in an imperative way of
loops, but more in the Erlang-way of list operations.  Initially
this is hard to achieve, but with any luck it will become a lot
easier once one is used to it.  Elegance, here I come!</p>
<p>Example run:</p>
<pre tabindex="0"><code>4&gt; random_matrix(6,7).  
[[0,1,4,6,7,4],
 [3,0,5,7,5,4],
 [5,1,0,2,5,2],
 [4,2,4,0,3,1],
 [4,4,3,3,0,1],
 [5,7,3,2,2,0]]
</code></pre><p>Note: I have used <code>random:seed/0</code> above, as I am happy for the function
to return identical matrices on subsequent runs with the same
parameters. To get truly random results, that would have to be left
out. However, for my benchmarking purposes it saved me having to
save the matrix to a file and read it in, as I can easily generate
a new copy of the same matrix I used before.</p>
]]></content:encoded></item><item><title>Fast PFNETs in Erlang</title><link>https://ojmason.net/fast-pfnets-in-erlang/</link><guid isPermaLink="true">https://ojmason.net/fast-pfnets-in-erlang/</guid><pubDate>Sat, 14 Feb 2009 00:00:00 +0000</pubDate><category>programming</category><category>erlang</category><description>Introduction Pathfinder Networks (PFNETs) are networks derived from a graph representing proximity data. Basically, each node is connected to (almost) every other node by a weighted link, and that makes it hard to see what’s going on. The Pathfinder algorithm prunes the graph by removing links which are weighted higher than another path between the same nodes.
For example: A links to B with weight 5. A also links to C with weight 2, and C links to B with weight 2. Adding up the weights, A to B direct is 5, A to C to B is 4. Result: we remove the link from A to B, as the route via C is shorter. There are different ways to calculate the path lengths (using the Minkowski r-metric), but you get the general idea. The resulting PFNET has fewer links and is easier to analyse.</description><content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p><a href="http://en.wikipedia.org/wiki/Pathfinder_Networks">Pathfinder Networks</a>
(PFNETs) are networks derived from a graph
representing proximity data.  Basically, each node is connected to
(almost) every other node by a weighted link, and that makes it
hard to see what’s going on.  The Pathfinder algorithm prunes the
graph by removing links which are weighted higher than another path
between the same nodes.</p>
<p>For example: A links to B with weight 5.  A also links to C with
weight 2, and C links to B with weight 2.  Adding up the weights,
A to B direct is 5, A to C to B is 4.  Result: we remove the link
from A to B, as the route via C is shorter.  There are different
ways to calculate the path lengths (using the <a href="http://en.wikipedia.org/wiki/Minkowski_metric">Minkowski <em>r</em>-metric</a>),
but you get the general idea.  The resulting PFNET has fewer links
and is easier to analyse.</p>
<p>In Schvaneveldt (1990) an algorithm for computing PFNETs is given,
but it is rather complex and computationally intensive.  There is
an improved algorithm called Binary Pathfinder, but that is apparently
more memory intensive.  Not very promising so far, but then along
comes <em>A new variant of the Pathfinder algorithm to generate large
visual science maps in cubic time</em>, by Quirin, Cordón, Santamaría,
Vargas-Quesada, and Moya-Anegón.  This algorithm is a lot faster
(by about 450 times), but has one disadvantage: speed is traded in
for flexibility.  The original Pathfinder algorithm has two parameters,
<em>r</em> (the value of the Minkowski metric to be used) and <em>q</em> (the maximum
length of paths to be considered).  The fast algorithm only has <em>r</em>,
and always uses the maximum value for <em>q</em> (which is n-1).  I know too
little about the application of PFNETs to say whether this is
important at all; for the uses I can envisage it does not seem to
matter.</p>
<p>As added bonus, the algorithm in pseudo code in Quirin et al. is
very short and straightforward.  They’re using a different <a href="http://en.wikipedia.org/wiki/Floyd-Warshall_algorithm">shortest-path
algorithm</a>
to identify, erm, shorter paths.  And then it’s very
simple to prune the original network.</p>
<p>A picture tells more than 1K words, so here instead of 2000 words
the before and after, graph layout courtesy of the graphviz program:</p>
<p>A network example (from Schvaneveldt 1990)</p>
<figure><picture>
    <source type="image/webp" srcset="/fast-pfnets-in-erlang/pfnets-1_hu_408d986bffc0e50.webp">
    <img src="/fast-pfnets-in-erlang/pfnets-1.png" width="300" height="261"
         alt="Fig 1. A network example (from Schvaneveldt 1990)"
         loading="lazy" decoding="async">
  </picture><figcaption>Fig 1. A network example (from Schvaneveldt 1990)</figcaption></figure><p>Here, each node is linked to every other node.  Running the PFNET
algorithm on it, we get the output shown in the second figure.</p>
<p>A PFNET generated from the previous graph:</p>
<figure><picture>
    <source type="image/webp" srcset="/fast-pfnets-in-erlang/pfnets-2_hu_97aab20883a17c23.webp">
    <img src="/fast-pfnets-in-erlang/pfnets-2.png" width="300" height="244"
         alt="Fig 2. A PFNET generated from the previous graph"
         loading="lazy" decoding="async">
  </picture><figcaption>Fig 2. A PFNET generated from the previous graph</figcaption></figure><p>If you compare the output with the actual result from Schvaneveldt’s
book (p.6 / 7), you’ll realise that it is not identical, and the
reason for that is that the example there limits the path-length,
using the parameters (<em>r</em> = 1, <em>q</em> = 2) rather than (<em>r</em> = 1, <em>q</em> = n-1)
as in the example shown here.  As a consequence, the link from N1
to N4 (with a weight of 5) disappears, because of the shorter path
(N1-N2-N3-N4, weight 4).  But that path is too long if <em>q</em> is just
2, and so it is kept in Schvaneveldt’s example.</p>
<h2 id="implementation">Implementation</h2>
<p>It is not possible to implement the pseudo-code given in Quirin <em>et
al</em> directly (in Erlang), as they use destructive updates of the link matrix,
which we obviously cannot do in Erlang.  But the first, naïve,
implementation is still quite short.  The input graph is represented
as a matrix (<em>n</em> x <em>n</em>) where each value stands for the link weight,
with zero being used to indicate non-existing links.  I have written
a function that creates a dot file from a matrix, which is then fed
into graphviz for generating images as the ones shown above.</p>
<p>There are basically two steps: creating a matrix of shortest paths
from the input matrix, and then generating the PFNET by comparing
the two matrices; if a certain cell has the same value in both
matrices, then it is a shortest path and is kept, otherwise there
is a shorter path and it’s pruned. Here is the main function:</p>
<pre tabindex="0"><code>find_path(Matrix) -&gt;
    Shortest = loop1(1,length(Matrix),Matrix),
    generate_pfnet(Matrix, Shortest, []).
</code></pre><p>Next we have the three loops (hence ‘cubic time’!) of the Floyd-Warshall
shortest path algorithm to create the shortest path matrix:</p>
<pre tabindex="0"><code>loop1(K,N,Matrix) when K &gt; N -&gt; 
    Matrix;
loop1(K,N,Matrix) -&gt;
    NewMatrix = loop2(K,1,Matrix,
        Matrix,[]),
    loop1(K+1,N,NewMatrix).

loop2(_,_,_,[],Acc) -&gt;
    lists:reverse(Acc);
loop2(K,I,D,[Row|Rest],Acc) -&gt;
    NewRow = loop3(K,I,1,D, Row, []),
    loop2(K,I+1,D,Rest,[NewRow|Acc]).

loop3(_,_,_,_, [], Acc) -&gt;
    lists:reverse(Acc);
loop3(K,I,J,D, [X|Rest], Acc) -&gt;
    loop3(K,I,J+1,D, Rest,
    [min(X, get(I,K,D) + get(K,J,D))|Acc]).
</code></pre><p>The final line implements the Minkowski metric with <em>r</em> = 1; this
could be expanded to include other values as well, eg <em>r</em> = 2 for
Euclidean, or <em>r</em> = ∞ (which seem to be the most common values in
use; the latter means using the maximum weight of any path component
along the full path).</p>
<p>And here are two utility methods, one to find the smaller of two
values, and one to retrieve an element from a matrix (which is a
list of rows).  There is something of a hack to deal with the fact
that zero does not mean a very small weight, but refers to a
non-existing link:</p>
<pre tabindex="0"><code>min(X, Y) when X &lt; Y -&gt; X;
min(_X, Y) -&gt; Y.

get(Row, Col, Matrix) -&gt;
    case lists:nth(Col,
      lists:nth(Row, Matrix)) of
        0 -&gt; 999999999;
        X -&gt; X
    end.
</code></pre><p>And finally, generating the PFNET by comparing the two matrices
(again, awful hack included):</p>
<pre tabindex="0"><code>generate_pfnet([],[],Result) -&gt;
    lists:reverse(Result);
generate_pfnet([R1|Rest1], [R2|Rest2], Acc) -&gt;
    Row = generate_pfrow(R1,R2,[]),
    generate_pfnet(Rest1, Rest2, [Row|Acc]).

generate_pfrow([],[],Result) -&gt;
    lists:reverse(Result);
generate_pfrow([C|Rest1], [C|Rest2], Acc) -&gt;
    case C of
        999999999 -&gt; C1 = 0;
        _ -&gt; C1 = C
    end,
    generate_pfrow(Rest1, Rest2, [C1|Acc]);
generate_pfrow([C1|Rest1], [C2|Rest2], Acc) -&gt;
    generate_pfrow(Rest1, Rest2, [0|Acc]).
</code></pre><h2 id="discussion">Discussion</h2>
<p>So this is the basic code.  It works, but there is scope for improvement.</p>
<ul>
<li>it only currently generates PFNETs with (<em>r</em> = 1, <em>q</em> = <em>n</em>-1)</li>
<li>there is no parallelism, hence it’s not really making use of Erlang’s strengths.</li>
<li>the three loops don’t look very elegant, and could probably be replaced by list comprehensions</li>
</ul>
<p>Because of the matrix being updated, it doesn’t look that easy to
parallelise the processing, but it would work at the level of
updating the individual rows.  If that can be done in parallel, it
would probably provide some speed-up (provided the matrix is not
of a trivial size).  So the first step would be to change the matrix
processing using <code>lists:map/2</code>, and replacing this then by <code>pmap</code>.</p>
<p>Once the code is up to scratch with full parallelism, and tested
on larger matrices I will probably put it up on Google Code in case
other people are interested in using it.  If you have any suggestions,
tell me in the comments!</p>
<h2 id="references">References</h2>
<dl>
<dt>Schvaneveldt, R. W. (Ed.) (1990)</dt>
<dd>Pathfinder Associative Networks: Studies in Knowledge Organization. Norwood, NJ: Ablex.
The book is out of print. A copy can be downloaded from the <a href="http://en.wikipedia.org/wiki/Pathfinder_Networks">Wikipedia page</a></dd>
<dt>Quirin, A; Cordón, O; Santamaría, J; Vargas-Quesada, B; Moya-Anegón, F (2008)</dt>
<dd>“A new variant of the Pathfinder algorithm to generate large visual science maps in cubic time”, Information Processing and Management, 44, p.1611-1623.</dd>
</dl>
]]></content:encoded></item><item><title>Kids and Computers</title><link>https://ojmason.net/kids-and-computers/</link><guid isPermaLink="true">https://ojmason.net/kids-and-computers/</guid><pubDate>Tue, 08 Jul 2008 00:00:00 +0000</pubDate><category>programming</category><category>children</category><description>Update: This did not turn out as I hoped. The main reason being that an old ZX Spectrum pre-dates the common availability of the Internet, and as soon as it was switched on the question arose, how one could watch YouTube videos on this machine. So, abject failure. Times have moved on, kids these days don&rsquo;t know they&rsquo;re born, good old days, it was so much better when I was young, spoilt kids nowadays etc etc etc.</description><content:encoded><![CDATA[<p><em>Update:</em> This did not turn out as I hoped. The main reason being that an old ZX Spectrum
pre-dates the common availability of the Internet, and as soon as it was switched on the
question arose, how one could watch YouTube videos on this machine. So, abject failure.
Times have moved on, kids these days don&rsquo;t know they&rsquo;re born, good old days, it was so much
better when I was young, spoilt kids nowadays etc etc etc.</p>
<hr>
<p>Like many(?) computer people of my generation I started off with
the Sinclair ZX81, and then continued with the ZX Spectrum and
onwards to an Amstrad CPC, learning BASIC and Z80 machine code
(because those machines were actually pretty slow).  This also means
that I treat computers as tools, not passively using programs other
people have written, but writing my own stuff.  In time I moved on
with languages, from Pascal to C, a bit of Prolog, C++, Java, and
now Erlang.  But those endless hours typing in program listings in
BASIC have surely benefitted me.  Learning by doing.  Type in small
programs, change the code, observe what happens.</p>
<p>My oldest daughter is seven, still half my age when I started with
computers, but from next year onwards they have ICT classes at
school; these basically seem to be ‘how to change fonts in MS Word’.
So I thought I’d better show her that a computer program is something
you write, not just something you use.  The only problem was, how
to do it?  Despite all its faults, BASIC seems to me to be a good
language to start with.  True, it has few control structures or
abstract data types, but it reads almost like English, and is only
a starting point after all.  And it’s only a first step in any case.</p>
<p>The next question is how to get her interested.  Using a PC seems
like overkill, and you need to boot it up, and shut it down, and
then start a development environment etc.  And I guess it’s not
that easy to use graphics or sound as it was on the old Spectrum.
So, I went to ebay and bought a ZX Spectrum +2 for about £7.  You
plug it in, it’s on.  You can start typing.  You’re finished, you
unplug it.  No files to get corrupted.  And it’s got a built-in
tape recoder for storage.</p>
<p>And, she is really excited.  It’s her very own computer, and she
already knows several commands.  All I need now is a few books with
BASIC programs, so that she has some material to type in.  In the
meantime I go with her through the manual, explaining the new
keywords, and she can already understand how a program is executed.
With any luck she’ll get hooked, especially once she learns how to
do graphics with it.  And the little games (‘guess the number’) are
also the right level for her, and maybe even her sisters.</p>
<p>The only problem I can see is printing.  But I’ve got an emulator
on my laptop, which might be able to read in something she saves,
and I might be able to take it from there.</p>
]]></content:encoded></item><item><title>Programming and the Tower of Babel</title><link>https://ojmason.net/programming-and-tower-of-babel/</link><guid isPermaLink="true">https://ojmason.net/programming-and-tower-of-babel/</guid><pubDate>Sat, 31 May 2008 00:00:00 +0000</pubDate><category>programming</category><description>Update: I originally posted this article in May 2008, but it is still relevant. I have kind of found a solution that I&rsquo;m trying out now, namely moving to a fairly minimalist language, Scheme. It is well suited to the main area I work in (NLP/AI), can be used purely functionally, and has such a simple syntax that it should be relatively easy to write run-times for it on various platforms if necessary.</description><content:encoded><![CDATA[<p><em>Update:</em> I originally posted this article in May 2008, but it is still relevant. I have kind of
found a solution that I&rsquo;m trying out now, namely moving to a fairly minimalist language, Scheme.
It is well suited to the main area I work in (NLP/AI), can be used purely functionally, and has
such a simple syntax that it should be relatively easy to write run-times for it on various platforms
if necessary.</p>
<p>In the meantime, however, the need for using different platforms has become less pressing for me, as
I mainly do this as a work-related hobby nowadays.</p>
<hr>
<p>I’m having a problem with languages. Not that there is something I
cannot do in my favourite language, but rather that there are
distinct ecosystems for various languages, and they are usually
fairly exclusive. For example, in order to program in a web context
you need either PHP, or alternatively be prepared to run your own
server if you want to use Java or Erlang. I’m not talking about
businesses or commercial operations here, just the private/academic/small
scale non-funded project range.</p>
<p>Most of the language processing software I’ve written is in Java,
because it works well and can run almost everywhere (but not on
shared webhosts). It’s useful to distribute applications, as people
can use it on Linux, Macs and even Windows. But I’ve now pretty
much switched to Erlang, as I put high hopes on the future of
parallel programming, and I want my software to take advantage of
multi-core processors. However, Erlang programs are not as easily
shared and distributed as Java apps are. Problem.</p>
<p>Ideally I’d like to write all my programs only once. This was kind
of the promise of Java, and it worked mostly. At some point I even
considered working on an interpreter for JVM bytecode written in
PHP (so that my Java classes would work without having to be re-coded
in PHP itself), but aside from the possibly terrible performance
it seemed too daunting a project. Maybe Erlang could be compiled
into JVM bytecodes? Of course you’d lose all the concurrency features
etc, but at least you could deploy it together with a Java app. A
bit like Scala, almost. <em>Update:</em> There is a (defunct?) project
that does attempt exactly that: <a href="https://github.com/trifork/erjang">Erlang on the JVM</a>.</p>
<p>If PHP wasn’t such a ghastly language I’d be happy to code everything
in that, but it seems too much of a sacrifice. But for most purposes
I would need at least those three:</p>
<ul>
<li>Java for applications to be deployed to other people</li>
<li>PHP for stuff running on shared webservers</li>
<li>Erlang for research and cutting-edge stuff</li>
</ul>
<p>And there is little to no common ground between them. Sigh.</p>
]]></content:encoded></item></channel></rss>