nomeata’s mind shares
http://www.joachim-breitner.de//blog
Joachim Breitners Denkblogadehttp://joachim-breitner.de/avatars/avatar_128.pngnomeata’s mind shares
http://www.joachim-breitner.de//blog
128128Explicit vertical alignment in Haskell
http://www.joachim-breitner.de/blog/704-Explicit_vertical_alignment_in_Haskell
http://www.joachim-breitner.de/blog/704-Explicit_vertical_alignment_in_Haskellhttp://www.joachim-breitner.de/blog/704-Explicit_vertical_alignment_in_Haskell#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Chris Done’s automatic Haskell formatter <a href="https://github.com/chrisdone/hindent"><code>hindent</code></a> is released in a new version, and getting quite a bit of deserved attention. He is polling the Haskell programmers on whether two or four spaces are the right indentation. But that is just cosmetics…</p>
<p>I am in principle very much in favor of automatic formatting, and I hope that a tool like <code>hindent</code> will eventually be better at formatting code than a human.</p>
<p>But it currently is not there yet. Code is literature meant to be read, and good code goes at length to be easily readable, and formatting can carry semantic information.</p>
<p>The Haskell syntax was (at least I get that impression) designed to allow the authors to write nicely looking, easy to understand code. One important tool here is vertical alignment of corresponding concepts on different lines. Compare</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">maze ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>
maze x y
<span class="fu">|</span> abs x <span class="fu">></span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">></span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">0</span>
<span class="fu">|</span> abs x <span class="fu">==</span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">==</span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">2</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">3</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">3</span>
<span class="fu">|</span> x <span class="fu">>=</span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">&&</span> y <span class="fu">==</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">4</span>
<span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dv">2</span></code></pre>
<p>with</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">maze ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>
maze x y
<span class="fu">|</span> abs x <span class="fu">></span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">></span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">0</span>
<span class="fu">|</span> abs x <span class="fu">==</span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">==</span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">2</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">3</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">3</span>
<span class="fu">|</span> x <span class="fu">>=</span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">&&</span> y <span class="fu">==</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">4</span>
<span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dv">2</span></code></pre>
<p>The former is a quick to grasp specification, the latter (the output of <code>hindent</code> at the moment) is a desert of numbers and operators.</p>
<p>I see two ways forward:</p>
<ul>
<li>Tools like <code>hindent</code> get improved to the point that they are able to detect such patterns, and indent it properly (which would be great, but very tricky, and probably never complete) or</li>
<li>We give the user a way to indicate intentional alignment in a non-obtrusive way that gets detected and preserved by the tool.</li>
</ul>
<p>What could such ways be?</p>
<ul>
<li>For guards, it could simply detect that within one function definitions, there are multiple <code>|</code> on the same column, and keep them aligned.</li>
<li><p>More general, one could take the approach <a href="https://github.com/chrisdone/hindent"><code>lhs2Tex</code></a> (which, IMHO, with careful input, a proportional font and with the great <a href="https://www.ctan.org/pkg/polytable"><code>polytable</code> LaTeX backend</a>, produces the most pleasing code listings) takes. There, two spaces or more indicate an alignment point, and if two such alignment points are in the same column, their alignment is preserved – even if there are lines in between!</p>
<p>With the latter approach, the code up there would be written</p>
<pre class="sourceCode haskell"><code class="sourceCode haskell"><span class="ot">maze ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>
maze x y
<span class="fu">|</span> abs x <span class="fu">></span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">></span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">0</span>
<span class="fu">|</span> abs x <span class="fu">==</span> <span class="dv">4</span> <span class="fu">||</span> abs y <span class="fu">==</span> <span class="dv">4</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">2</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">1</span>
<span class="fu">|</span> x <span class="fu">==</span> <span class="dv">3</span> <span class="fu">&&</span> y <span class="fu"><=</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">3</span>
<span class="fu">|</span> x <span class="fu">>=</span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">&&</span> y <span class="fu">==</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dv">4</span>
<span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dv">2</span></code></pre>
<p>And now the intended alignment is explicit.</p></li>
</ul>
<p>(This post is <a href="https://www.reddit.com/r/haskell/comments/5059gm/hindent_5_one_style_to_rule_them_all/d72k1ci">cross-posted on reddit</a>.)</p>Tue, 30 Aug 2016 09:35:18 -0400HaL deadline extended
http://www.joachim-breitner.de/blog/701-HaL_deadline_extended
http://www.joachim-breitner.de/blog/701-HaL_deadline_extendedhttp://www.joachim-breitner.de/blog/701-HaL_deadline_extended#commentsmail@joachim-breitner.de (Joachim Breitner)<p>There is this long-running workshop series <strong>Haskell in Leipzig</strong>, which is a meeting of all kinds of Haskell-interested folks (beginners, experts, developers, scientists), and for year’s instance, <a href="http://hal2016.haskell.org/">HaL 2016</a>, I have the honour of being the program committee chair.</p>
<p>The original deadline passed last week, and after looking through the submissions it became clear that although the quality was good, the quantitiy was still lacking. I therefore extended the submission deadline by two weeks, until <strong>July 15th</strong>.</p>
<p>So if you have something worth talking about, please do submit a proposal<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> and come to Leipzig!.</p>
<p>Why should you submit here? Because it gives you a platform to talk about your ideas to an audience that usually does not consist just of your fellow speakers, as it is often with purely academic workshops, but “real” listeners of various kinds. And it is a fun event.</p>
<p>And why should you come to Leipzig? Because of all the interesting talks and tutorials! Of course I cannot say a lot here yet, besides that our invited speaker <a href="http://www.cse.chalmers.se/~russo/"><strong>Alejandro Russo</strong></a> from Chalmers and Gothenburg University will present his work on information-flow control in Haskell (i.e., SecLib, LIO, MAC, HLIO).</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>And if you want to save me from sleepless nights, submit the first version a few days before the deadline…<a href="#fnref1">↩</a></p></li>
</ol>
</div>Tue, 05 Jul 2016 19:40:11 +0200GHC performance is rather stable
http://www.joachim-breitner.de/blog/693-GHC_performance_is_rather_stable
http://www.joachim-breitner.de/blog/693-GHC_performance_is_rather_stablehttp://www.joachim-breitner.de/blog/693-GHC_performance_is_rather_stable#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Johannes Bechberger, while working on <a href="http://pp.ipd.kit.edu/thesis.php?id=261">his Bachelor’s thesis</a> supervised by my colleague <a href="http://pp.ipd.kit.edu/personhp/andreas_zwinkau.php">Andreas Zwinkau</a>, has developed a performance benchmark runner and results visualizer called “<a href="https://github.com/parttimenerd/temci">temci</a>”, and used GHC as a guinea pig. You can read <a href="https://uqudy.serpens.uberspace.de/blog/2016/02/08/ghc-performance-over-time/">his elaborate analysis</a> on his blog.</p>
<p>This is particularly interesting given recent discussions about GHC itself becoming slower and slower, as for example observed by <a href="https://mail.haskell.org/pipermail/haskell-cafe/2016-January/122655.html">Johannes Waldmann</a> and <a href="https://twitter.com/a_cowley/status/692481516744634368">Anthony Cowley</a>.</p>
<p>Johannes Bechberger’s take-away is that, at least for the programs at hand (which were taken from the <a href="http://benchmarksgame.alioth.debian.org/">The Computer Language Benchmarks Game</a>, there are hardly any changes worth mentioning, as most of the observed effects are less than a standard deviation and hence insignificant. He tries hard to distill some useful conclusions from the data; the one he finds are:</p>
<ul>
<li>Compile time does not vary significantly.</li>
<li>The compiler flag <code>-O2</code> indeed results in faster code than <code>-O</code>.</li>
<li>With <code>-O</code> (but not <code>-O2</code>), GHC 8.0.1 is better than GHC 7.0.1. Maybe some optimizations were promoted to <code>-O</code>?</li>
</ul>
<p>If you are interested, please head over to Johannes’s post and look at the gory details of the analysis and give him feedback on that. Also, maybe his tool <a href="https://github.com/parttimenerd/temci">temci</a> is something you want to try out?</p>
<p>Personally, I find it dissatisfying to learn so little from so much work, but as he writes: “It’s so easy to lie with statistics.”, and I might add “lie to yourself”, e.g. by ignoring good advise about standard deviations and significance. I’m sure my tool <a href="https://github.com/nomeata/gipeda">gipeda</a> (which powers <a href="https://github.com/nomeata/gipeda">perf.haskell.org</a>) is guilty of that sin.</p>
<p>Maybe a different selection of test programs would yield more insight; the benchmark’s games programs are too small and hand-optimized, the <a href="http://git.haskell.org/nofib.git">nofib programs</a> are plain old and the <a href="http://git.haskell.org/nofib.git/tree/HEAD:/fibon">fibon collection</a> has bitrotted. I would love to see a curated, collection of real-world programs, bundled with all dependencies and frozen to allow meaningful comparisons, but updated to a new, clearly marked revision, on a maybe bi-yearly basis – maybe Haskell-SPEC-2016 if that were not a <a href="https://www.spec.org/spec/trademarks.html">trademark infringement</a>.</p>Tue, 09 Feb 2016 16:17:43 +0100A multitude of early Christmas presents
http://www.joachim-breitner.de/blog/690-A_multitude_of_early_Christmas_presents
http://www.joachim-breitner.de/blog/690-A_multitude_of_early_Christmas_presentshttp://www.joachim-breitner.de/blog/690-A_multitude_of_early_Christmas_presents#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Today was a nice day with a surprising number of early Christmas presents:</p>
<ul>
<li><p>I submitted my Ph.D. thesis “Lazy Evaluation: From formal semantics to to a machine-checked compiler transformation” about an Isabelle formalisation of Launchbury’s natural semantics (also found in the <a href="http://afp.sourceforge.net/entries/Launchbury.shtml">Launchbury entry</a> in the Archive of Formal Proofs), about the GHC optimization “Call Arity” that I developed (see the <a href="http://link.springer.com/chapter/10.1007/978-3-319-14675-1_3">TFP 2014 paper</a>) and a formal proof that it is indeed an optimization (<a href="http://dx.doi.org/10.1145/2804302.2804312">Haskell Symposium 2015 paper</a>, <a href="http://afp.sourceforge.net/entries/Call_Arity.shtml">AFP entry</a>). After 243 pages, it is finally done and I can now turn to new things.</p>
<p>Speaking of “something new”: I’m hunting jobs right now. I am in particular interested in academic post-doc positions in my field (functional programming languages and/or interactive theorem proving), but I’d also like to hear about attractive non-academic positions that fit my profile.</p></li>
<li><p>Someone who I value and respect a lot asked me to co-author a paper with him. I am not sure whether further details at this stage belong to a public blog post, so I’ll keep them back. But nevertheless this is very nice.</p></li>
<li><p>A <a href="http://pp.ipd.kit.edu/publication.php?id=irlsod16">paper on information flow control</a> by my colleagues Jürgen Graf, Martin Hecker and Martin Mohr, my advisor Gregor Snelting and (although only marginally) me was accepted at POST 2016, and the notification reached us today.</p></li>
<li><p>Together with Carsten Podszun, I have written an article about the Ravensburger Tip-toi pen and <a href="http://www.heise.de/make/inhalt/2015/6/108/">how to create your own books</a> for that using the <a href="http://tttool.entropia.de/">tttool program</a> that I have created for the German magazine <a href="http://www.heise.de/make"><em>Make:</em></a>, and it is included in issue 6/2015, which arrived today in my mailbox.</p></li>
<li><p><a href="http://incredible.nomeata.de/">The Incredible Proof Machine</a> attracts new contributors. Well, <a href="https://github.com/nomeata/incredible/pull/74">one</a>. But a few days ago, I heard that <a href="https://twitter.com/mjdominus/status/675673521255788544">a 11½ year old girl</a> has great fun with it!</p></li>
<li><p>Tonight, my group is having their Christmas party and I can expect to be fed well by home-cooked Mexican something. Got to go...</p></li>
</ul>Fri, 18 Dec 2015 17:38:05 +0100HaL 10
http://www.joachim-breitner.de/blog/689-HaL_10
http://www.joachim-breitner.de/blog/689-HaL_10http://www.joachim-breitner.de/blog/689-HaL_10#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Today I had the honour to hold my first invited talk: I was the keynote speaker at the <a href="http://nfa.imn.htwk-leipzig.de/HAL2015/">tenth Haskell in Leipzig workshop</a>. I chose to present how I used the <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad-Fix.html">MonadFix</a> type class to conveniently and by-construction-correctly calculate offsets while serialising to a binary data format in the implementation of <a href="http://tttool.nomeata.de/">tttool</a>. Johannes Waldmann could not resist to point out that MonadFix was already a topic at the very first HaL meeting nine years ago, but nevertheless I think that my live-coded slide-less talk was quite suitable for the given audience of roughly 55 attendees.</p>
<p>I have uploaded a <a href="http://joachim-breitner.de/publications/MonadFix_HaL10_2015-12-04.pdf">transcript of this talk</a>.</p>Fri, 04 Dec 2015 23:04:33 +0100Constructing a list in a monad revisited
http://www.joachim-breitner.de/blog/684-Constructing_a_list_in_a_monad_revisited
http://www.joachim-breitner.de/blog/684-Constructing_a_list_in_a_monad_revisitedhttp://www.joachim-breitner.de/blog/684-Constructing_a_list_in_a_monad_revisited#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Two years ago, I <a href="https://www.joachim-breitner.de/blog/620-Constructing_a_list_in_a_Monad">discussed</a> various ways of constructing a list in a Monad (or, more specifically, in IO) in Haskell, and compared their merits in terms of elegance, stack usage, number of traversals of the list and run-time efficiency.</p>
<p>Recently, two blog posts discussed the issue further and proposed new, more daring alternatives. <a href="http://neilmitchell.blogspot.co.uk/2015/09/making-sequencemapm-for-io-take-o1-stack.html">Neil Mitchell</a> breaks through the abstraction provided by <code>IO</code>, duplicates “the world” and traverses the list twice, and obtains a speed-up for long lists.</p>
<p><a href="http://twanvl.nl/blog/haskell/unsafe-sequence">Twarn van Laarhoven</a> went even further and wrote custom C-- code to destructively update the tail-pointer of the list cell to be able to create the list completely evaluated on the first start. This basically answers my question from two years ago:</p>
<blockquote>
<p>I’m still wondering: What would be required from Haskell, GHC or the monads in question to have a fully satisfactory solution here, i.e. one that is as fast as the naive recursion, as stack efficient as the difference list solution, and allocates no thunks, only list cells?</p>
</blockquote>
<p>He also has a variant with a slightly nicer interface around “holes”, i.e. explicit objects on the heap that can later be replaced by indirections. Obviously, both approaches are very unsafe.</p>
<p>I took this as an opportunity to redo my benchmark measurements, and include their variants (named <code>escapeIO</code>, <code>hackIO</code> and <code>holeIO</code>). The following table omits the variants with quadratic performance, as I ran it on longer lists now:</p>
<table>
<thead>
<tr class="header">
<th align="left">Variant</th>
<th align="right">10^0</th>
<th align="right">10^1</th>
<th align="right">10^2</th>
<th align="right">10^3</th>
<th align="right">10^4</th>
<th align="right">10^5</th>
<th align="right">10^6</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td align="left">accumReverse</td>
<td align="right">37ns</td>
<td align="right">153ns</td>
<td align="right">1134ns</td>
<td align="right">12µs</td>
<td align="right">208µs</td>
<td align="right">8540µs</td>
<td align="right">97ms</td>
</tr>
<tr class="even">
<td align="left">recursion</td>
<td align="right">29ns</td>
<td align="right">139ns</td>
<td align="right">680ns</td>
<td align="right">6790ns</td>
<td align="right">160µs</td>
<td align="right">6441µs</td>
<td align="right">76ms</td>
</tr>
<tr class="odd">
<td align="left">replicateM</td>
<td align="right">26ns</td>
<td align="right">126ns</td>
<td align="right">677ns</td>
<td align="right">6785ns</td>
<td align="right">168µs</td>
<td align="right">6314µs</td>
<td align="right">78ms</td>
</tr>
<tr class="even">
<td align="left">accumDList</td>
<td align="right">35ns</td>
<td align="right">165ns</td>
<td align="right">995ns</td>
<td align="right">10µs</td>
<td align="right">190µs</td>
<td align="right">9706µs</td>
<td align="right">100ms</td>
</tr>
<tr class="odd">
<td align="left">streams</td>
<td align="right">27ns</td>
<td align="right">136ns</td>
<td align="right">691ns</td>
<td align="right">6788ns</td>
<td align="right">173µs</td>
<td align="right">5771µs</td>
<td align="right">75ms</td>
</tr>
<tr class="even">
<td align="left">unsafeInterleave</td>
<td align="right">60ns</td>
<td align="right">329ns</td>
<td align="right">2804ns</td>
<td align="right">28µs</td>
<td align="right">373µs</td>
<td align="right">5605µs</td>
<td align="right">57ms</td>
</tr>
<tr class="odd">
<td align="left">listFix</td>
<td align="right">51ns</td>
<td align="right">412ns</td>
<td align="right">4109ns</td>
<td align="right">56µs</td>
<td align="right">2761µs</td>
<td align="right">42ms</td>
<td align="right">445ms</td>
</tr>
<tr class="even">
<td align="left">escapeIO</td>
<td align="right">41ns</td>
<td align="right">187ns</td>
<td align="right">1808ns</td>
<td align="right">16µs</td>
<td align="right">234µs</td>
<td align="right">4409µs</td>
<td align="right">45ms</td>
</tr>
<tr class="odd">
<td align="left">hackIO</td>
<td align="right">30ns</td>
<td align="right">152ns</td>
<td align="right">1199ns</td>
<td align="right">11µs</td>
<td align="right">140µs</td>
<td align="right">3701µs</td>
<td align="right">42ms</td>
</tr>
<tr class="even">
<td align="left">holeIO</td>
<td align="right">40ns</td>
<td align="right">222ns</td>
<td align="right">1725ns</td>
<td align="right">17µs</td>
<td align="right">218µs</td>
<td align="right">4446µs</td>
<td align="right">53ms</td>
</tr>
</tbody>
</table>
<p>The following graph shows that around 10000, the naive approaches become much slower and the fancy hacks pay of, with Twarn’s tail-pointer-updating code performing the best:</p>
<div class="figure">
<img src="https://raw.githack.com/nomeata/list-producing-monads/master/graphs.svg" title="Benchmark plot" alt="Benchmark plot"/><p class="caption"><a href="https://raw.githack.com/nomeata/list-producing-monads/master/graphs.svg">Benchmark plot</a></p>
</div>
<p>I would really like to see a package that provides a API like Twarn’s holes, either in this raw unsafe variant (but with the garbage collector related code checked), or with a safe API using type hackery similar to the <code>ST</code> monad that ensures that after “normal” code gets its hands on a term possibly involving holes, the holes may no longer be modified.</p>
<p>I have put <a href="https://github.com/nomeata/list-producing-monads">the code and results</a> on GitHub.</p>Wed, 14 Oct 2015 16:28:01 +0200Incredible Proof Machine put to the test
http://www.joachim-breitner.de/blog/683-Incredible_Proof_Machine_put_to_the_test
http://www.joachim-breitner.de/blog/683-Incredible_Proof_Machine_put_to_the_testhttp://www.joachim-breitner.de/blog/683-Incredible_Proof_Machine_put_to_the_test#commentsmail@joachim-breitner.de (Joachim Breitner)<p>I’m currently on the way home, returning from a four-day workshop for high school students; ages 13 to 20, grade 9 to 13. My goal was to teach them something about proofs and logic, in a ambitiously formal and abstract way. For this workshop, I created a computer program called “<a href="http://incredible.nomeata.de/">The Incredible Proof Machine</a>” that allows the kids to explore creating a proof, by placing blocks on a canvas and drawing connections between them (see <a href="//www.joachim-breitner.de/blog/682-incredible-proof-machine">my previous blog post</a> for an introduction).</p>
<p>Subtracting time spent on on breaks, organizational stuff, the time the student needed to prepare a final presentation, I think we were working for a total of 14 hours, during which we covered propositional logic. I generally let the students explore and try to solve the tasks of one session mostly on their own, followed by a common discussion of what they have just done, what it means why it makes sense etc. The sessions were: assumptions and conclusions in general, with conjunction; implication; disjunction; falsum and <em>tertium non datur</em>. We also briefly discussed “paper proofs” with the student: how they look, and how they relate to the Proof Machine proofs. We had some lecture notes that we handed out pice-wise after each session.</p>
<p>The sections were mildly<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> password-protected to avoid that the quicker students would work ahead, thus keeping the group together. One or two of the 13 students were doing very well and eventually, I gave them the passwords to the predicate logic section and let them work them on them on their own. The quickest managed to solve almost all of these as well, but (as far I as I can tell) without a deeper understanding of the quantifiers, and more a mechanical intuition.</p>
<p>As expected, the students were able to solve most of the exercises, even when a proper understanding of the logical semantics was not yet fully developed. This was by design: I believe that this way it was more motivating and encouraging, as they could “make it work”, compared to a more traditional approach of first throwing a lot of theory at them and then expecting them to apply it. This was confirmed by their feedback after the workshop.</p>
<p>I was happy with my implementation. The students immediately could work with it with very few hick-ups, and only one minor bug occurred<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a>, which I could fix on the spot. Having everything run on in the browser was a big plus, given that we had no stable internet connection for everyone: Once the Incredible Proof Machine was loaded, the student could continue to work offline.</p>
<p>Personally, I find that the UI is occasionally too sluggish, especially on the weaker laptops, but it seems that the students did not seem to mind. Some students tried to connect outputs with outputs or inputs with inputs and the visualization did make it clearly visible that such a link is not actually connected to the block. The predicate logic part is a bit less convincing, with e.g. scoping of local constants not easily understood. I would say that this part would work better if some explanation is given before the students start working on the more involved rules.</p>
<p>Our room was equipped with a smartboard, and I was delighted when I found out, mostly by accident, that I could actually use my finger to drag the blocks of the proof and to draw connections. This not only gave me a “Minority Report”-like feeling, but also meant that it was much easier for the students to follow my explanations when they could just watch my hand, instead of trying to locate the mouse pointer on a regular projector. I’m generally doubtful whether such fancy technological toys are useful in the class room, but in this case at least I liked it. The ability to scribble anywhere on the screen was occasionally a plus as well.</p>
<p>All in all I believe the Proof Machine was a useful tool, and I am sure that without it, it would have been tricky to have students voluntarily spend 14 hours on such a relatively dry and abstract topic. Given the amount of work that went into the development, I hope that this will not be the last occasion where it is put to good use. So if you have to teach formal logic and natural deduction-style proofs, you are welcome to use the Incredible Proof Machine to get your students excited. It is purely static, i.e. needs no special server-side infrastructure, and you can define your own logic (i.e. proof rules), sessions and tasks.</p>
<p>Also, there are a few interesting way in which the Proof Machine could be extended. In particular, I’d like it to be able to generate a “normal”, natural-language proof from a given proof – even if it will sound a bit mechanical – and then use hover-highlight effects to relate the formulas and sentences in the text proof to the connections and blocks in the graphical proof. Contributions are welcome!</p>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>JavaScript based with no crypto or even obfuscation in the code.<a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>Due to differences between the task specification as given in the code, and the task specification when normalizing the syntax of the terms, the proofs that the students created were lost when they re-loaded the page.<a href="#fnref2">↩</a></p></li>
</ol>
</div>Mon, 12 Oct 2015 22:16:35 +0200The Incredible Proof Machine
http://www.joachim-breitner.de/blog/682-The_Incredible_Proof_Machine
http://www.joachim-breitner.de/blog/682-The_Incredible_Proof_Machinehttp://www.joachim-breitner.de/blog/682-The_Incredible_Proof_Machine#commentsmail@joachim-breitner.de (Joachim Breitner)<p>In a few weeks, I will have the opportunity to offer a weekend workshop to selected and motivated high school students<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a> to a topic of my choice. My idea is to tell them something about logic, proofs, and the joy of searching and finding proofs, and the gratification of irrevocable truths.</p>
<p>While proving things on paper is already quite nice, it is much more fun to use an interactive theorem prover, such as <a href="http://isabelle.in.tum.de/">Isabelle</a>, <a href="https://coq.inria.fr/">Coq</a> or <a href="http://wiki.portal.chalmers.se/agda">Agda</a>: You get immediate feedback, you can experiment and play around if you are stuck, and you get lots of small successes. Someone<a href="#fn2" class="footnoteRef" id="fnref2"><sup>2</sup></a> once called interactive theorem proving “the worlds most geekiest videogame”.</p>
<p>Unfortunately, I don’t think one can get high school students without any prior knowledge in logic, or programming, or fancy mathematical symbols, to do something meaningful with a system like Isabelle, so I need something that is (much) easier to use. I always had this idea in the back of my head that proving is not so much about writing text (as in “normally written” proofs) or programs (as in Agda) or labeled statements (as in Hilbert-style proofs), but rather something involving facts that I have proven so far floating around freely, and way to combine these facts to new facts, without the need to name them, or put them in a particular order or sequence. In a way, I’m looking for labVIEW wrestled through the Curry-Horward-isomorphism. Something like this:</p>
<div class="figure">
<img src="//www.joachim-breitner.de/various/incredibe-proof.png" alt="A proof of implication currying"/><p class="caption">A proof of implication currying</p>
</div>
<p>So I set out, rounded up <a href="https://github.com/nomeata/incredible/graphs/contributors">a few contributors</a> (Thanks!), implemented this, and now I proudly present: <a href="http://incredible.nomeata.de/"><strong>The Incredible Proof Machine</strong></a><a href="#fn3" class="footnoteRef" id="fnref3"><sup>3</sup></a></p>
<p>This interactive theorem prover allows you to do perform proofs purely by dragging blocks (representing proof steps) onto the paper and connecting them properly. There is no need to learn syntax, and hence no frustration about getting that wrong. Furthermore, it comes with a number of example tasks to experiment with, so you can simply see it as a challenging computer came and work through them one by one, learning something about the logical connectives and how they work as you go.</p>
<p>For the actual workshop, my plan is to let the students <em>first</em> try to solve the tasks of one session on their own, let them draw their own conclusions and come up with an idea of what they just did, and <em>then</em> deliver an explanation of the logical meaning of what they did.</p>
<p>The implementation is heavily influenced by Isabelle: The software does not know anything about, say, conjunction (∧) and implication (→). To the core, everything is but an untyped lambda expression, and when two blocks are connected, it does unification<a href="#fn4" class="footnoteRef" id="fnref4"><sup>4</sup></a> of the proposition present on either side. This general framework is then instantiated by specifying the basic rules (or axioms) <a href="https://github.com/nomeata/incredible/blob/master/examples/logics/predicate.yaml">in a descriptive manner</a>. It is quite feasible to implement other logics or formal systems on top of this as well.</p>
<p>Another influence of Isabelle is the non-linear editing: You neither have to create the proof in a particular order nor have to manually manage a “proof focus”. Instead, you can edit any bit of the proof at any time, and the system checks all of it continuously.</p>
<p>As always, I am keen on feedback. Also, if you want to use this for your own teaching or experimenting needs, let me know. We have a <a href="https://lists.nomeata.de/mailman/listinfo/incredible">mailing list</a> for the project, the <a href="https://github.com/nomeata/incredible">code is on GitHub</a>, where you can also file <a href="https://github.com/nomeata/incredible/issues">bug reports and feature requests</a>. Contributions are welcome! All aspects of the logic are implemented in Haskell and compiled to JavaScript using <a href="https://github.com/ghcjs/ghcjs">GHCJS</a>, the UI is plain hand-written and messy JavaScript code, using <a href="http://jointjs.com/">JointJS</a> to handle the graph interaction.</p>
<p>Obviously, there is still plenty that can be done to improve the machine. In particular, the ability to create your own proof blocks, such as proof by contradiction, prove them to be valid and then use them in further proofs, is currently being worked on. And while the page will store your current progress, including all proofs you create, in your browser, it needs better ways to save, load and share tasks, blocks and proofs. Also, we’d like to add some gamification, i.e. achievements (“First proof by contradiction”, “50 theorems proven”), statistics, maybe a “share theorem on twitter” button. As the UI becomes more complicated, I’d like to investigating moving more of it into Haskell world and use Functional Reactive Programming, i.e. <a href="https://github.com/ryantrinkle/reflex">Ryan Trickle’s reflex</a>, to stay sane.</p>
<p>Customers who liked <strong>The Incredible Proof Machine</strong> might also like these artifacts, that I found while looking whether something like this exists:</p>
<ul>
<li><a href="http://easyprove.ii.uni.wroc.pl/wiki">Easyprove</a>, an interactive tool to create textual proofs by clicking on rules.</li>
<li><a href="http://www.winterdrache.de/freeware/domino/index.html">Domino On Acid</a> represents natural deduction rules in propositional logic with → and ⊥ as a game of dominoes.</li>
<li><a href="http://proofscape.org/">Proofscape</a> visualizes the dependencies between proofs as graphs, i.e. it operates on a higher level than <strong>The Incredible Proof Machine</strong>.</li>
<li><a href="http://proofscape.org/">Proofmood</a> is a nice interactive interface to conduct proofs in Fitch-style.</li>
<li><a href="http://cseweb.ucsd.edu/~lerner/proof-game/">Polymorphic Blocks</a> represents proofs trees in a sequent calculus with boxes with different shapes that have to match.</li>
<li><a href="http://japeforall.org.uk/">JAPE</a> is an editor for proofs in a number of traditional proof styles. (Thanks to Alfio Martini for the pointer.)</li>
<li><a href="http://logitext.mit.edu/main">Logitext</a>, written by Edward Z. Yang, is an online tool to create proof trees in sequent style, with a slick interface, and is even backed by Coq! (Thanks to Lev Lamberov for the pointer.)</li>
<li><a href="http://gleachkr.github.io/Carnap/">Carnap</a> is similar in implementation to <strong>The Incredible Proof Machine</strong> (logical core in Haskell, generic unification-based solver). It currently lets you edit proof trees, but there are <a href="https://github.com/gleachkr/Carnap/issues/13">plans</a> to create something more visual.</li>
<li><a href="http://selier.net/ndapp/">Clickable Proofs</a> is a (non-free) iOS app that incorporates quite a few of the ideas that are behind <strong>The Incredible Proof Machine</strong>. It came out of a Bachelor’s thesis of Tim Selier and covers propositional logic.</li>
<li><a href="http://euclidthegame.com/">Euclid the game</a> by Kasper Peulen is a nice game to play with geometric constructions.</li>
<li><a href="http://globular.science/">Globular</a>, a web-base proof assistent for “finitely-presented semistrict globular higher categories”.</li>
<li><a href="https://github.com/wandernauta/viskell">Viskell</a> is not about proofs, but rather about functional programs, but according to Horward-Curry, that’s the same thing, and their graphs look quite similar.</li>
</ul>
<div class="footnotes">
<hr/>
<ol>
<li id="fn1"><p>Students with migration background supported by the <a href="https://www.start-stiftung.de/stipendium.html">START scholarship</a><a href="#fnref1">↩</a></p></li>
<li id="fn2"><p>Does anyone know the reference?<a href="#fnref2">↩</a></p></li>
<li id="fn3"><p>We almost named it “Proofcraft”, which would be a name our current Minecraft-wild youth would appreciate, but it is alreay taken by <a href="http://proofcraft.org/">Gerwin Kleins blog</a>. Also, the irony of a theorem prover being in-credible is worth something.<a href="#fnref3">↩</a></p></li>
<li id="fn4"><p>Luckily, two decades ago, Tobias Nipkow <a href="http://www21.in.tum.de/~nipkow/pubs/lics93.html">published a nice implementation of higher order pattern unification</a> as ML code, which I transliterated to Haskell for this project.<a href="#fnref4">↩</a></p></li>
</ol>
</div>Thu, 24 Sep 2015 14:14:34 +0200Running circle-packing in the Browser, now using GHCJS
http://www.joachim-breitner.de/blog/680-Running_circle-packing_in_the_Browser%2C_now_using_GHCJS
http://www.joachim-breitner.de/blog/680-Running_circle-packing_in_the_Browser%2C_now_using_GHCJShttp://www.joachim-breitner.de/blog/680-Running_circle-packing_in_the_Browser%2C_now_using_GHCJS#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Quite a while ago, I wrote a small Haskell library called <a href="http://hackage.haskell.org/package/circle-packing">circle-packing</a> to pack circles in a tight arrangement. Back then, I used the Haskell to JavaScript compiler <a href="http://fay-lang.org/">fay</a> to create a <a href="http://darcs.nomeata.de/circle-packing/fay/fay-demo.html">pretty online demo</a> of that library, and shortly after, I create the <a href="http://darcs.nomeata.de/circle-packing/haste/haste-demo.html">identical demo</a> using <a href="https://github.com/valderman/haste-compiler">haste</a> (another Haskell to JavaScript compiler).</p>
<p>The main competitor of these two compilers, and the most promising one, is <a href="https://github.com/ghcjs/ghcjs">GHCJS</a>. Back then, it was too annoying to install. But after two years, things have changed, and it only takes a few simple commands to get GHCJS running, so I finally created the <a href="http://darcs.nomeata.de/circle-packing/ghcjs/ghcjs-demo.html">circle packing demo in a GHCJS variant</a>.</p>
<p>Quick summary: Cabal integration is very good (like haste, but unline fay), interfacing JavaScript is nice and easy (like fay, but unlike haste), and a quick check seems to indicate that it is faster than either of these two. I should note that I did not update the other two demos, so they represent the state of fay and haste back then, respectively.</p>
<p>With GHCJS now available at my fingertips, maybe I will produce some more Haskell to be run in your browser. For example, I could port <a href="https://www.joachim-breitner.de/blog/292-FrakView__An_Haskell_Renderer_for_Iterated_Function_Systems">FrakView</a>, a GUI program to render, expore and explain iterated function systems, from GTK to HTML.</p>Sat, 20 Jun 2015 22:50:09 +0200ZuriHac 2015
http://www.joachim-breitner.de/blog/678-ZuriHac_2015
http://www.joachim-breitner.de/blog/678-ZuriHac_2015http://www.joachim-breitner.de/blog/678-ZuriHac_2015#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Last weekend, I attended <a href="https://wiki.haskell.org/ZuriHac2015">ZuriHac 2015</a>, which was, as always, a pleasant event. I did not actually do a lot, besides some maintenance of Debian Haskell packages, but had some nice chats. It is always very motivating to hear that people read my blog, or that they found my talk (such as the <a href="http://vimeo.com/100166511">Haskell Bytes talk at Galois</a>) helpful.</p>
<p>My plan was to work on <a href="https://github.com/nomeata/gipeda">gipeda</a> and <a href="https://perf.haskell.org/">perf.haskell.org</a>. I did not do much until an hour before I had to leave, when Lennard Kolmodin came around and I showed him the software. He liked it so far, so we quickly set up an <a href="https://perf.haskell.org/">instance of gipeda for the “binary” library</a>. It is not finished yet, as more benchmarks need to be extracted from the build log. That was motivating, and I got further ideas to implement during the train ride back. If only that had happened earlier during the weekend...</p>Mon, 01 Jun 2015 11:37:19 +0200Fifth place in Godingame World Cup
http://www.joachim-breitner.de/blog/677-Fifth_place_in_Godingame_World_Cup
http://www.joachim-breitner.de/blog/677-Fifth_place_in_Godingame_World_Cuphttp://www.joachim-breitner.de/blog/677-Fifth_place_in_Godingame_World_Cup#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Last evening, <a href="http://codingame.com/">Codingame</a> held a “Programming World Cup” titled “<a href="http://www.codingame.com/leaderboards/challenge/there-is-no-spoon/">There is no Spoon</a>”. The format is that within four hours, you get to write a program that solves a given task. Submissions are first rated by completeness (there are 13 test inputs that you can check your code again, and further hidden tests that will only be checked after submission) and then by time of submission. You can only submit your code once.</p>
<p>What I like about Codingame is that they support a great number of programming languages in their Web-“IDE”, including Haskell. I had nothing better to do yesterday, so I joined. I was aiming for a good position in the Haskell-specific ranking.</p>
<p>After nearly two hours my code completed all the visible test cases and I submitted. I figured that this was a reasonable time to do so, as it was half-time and there are supposed to be two challenges. I turned out that the first, quite small task, which felt like a warm-up or qualification puzzle, was the first of those two, and that therefore I was done, and indeed the 5th fastest to complete a <a href="http://www.codingame.com/challengereport/12820309a78d5e19ca7b45da0269566474f102d">100% solution</a>! With only less than 5 minutes difference to the 3rd, money-winning place – if I had known I had such a chance, I had started on time...</p>
<p>Having submitted the highest ranked Haskell code, I will get a T-Shirt. I also defended Haskell’s reputation as an efficient programming language, ranked third in the contest, after C++ (rank 1) and Java (rank 2), but before PHP (9), C# (10) and Python (11), listing only those that had a 100% solution.</p>
<p>The task, solving a <a href="http://www.chiark.greenend.org.uk/~sgtatham/puzzles/js/bridges.html">Bridges puzzle</a>, did not feel like a great fit for Haskell at first. I was juggling <code>Data.Map</code>s around where otherwise I’d simple attach attributes to object, and a recursive function simulated nothing but a plain loop. But it played off the moment I had to implement guessing parts of the solution, trying what happens and backtracking when it did not work: With all state in parameters and pure code it was very simple to get a complete solution.</p>
<p><a href="https://gist.github.com/nomeata/bd85469dbde97f9a4348">My code</a> is of course not very polished, and having the main loop live in the <code>IO</code> monad just to be able to print diagnostic commands is a bit ugly.</p>
<p>The <a href="http://www.codingame.com/challenge/code-of-the-rings">next, Lord of the Ring-themed world cup</a> will be on June 27th. Maybe we will see more than 18 Haskell entries then?</p>Sun, 26 Apr 2015 15:01:14 +0200Talk and Article on Monads for Reverse Engineering
http://www.joachim-breitner.de/blog/676-Talk_and_Article_on_Monads_for_Reverse_Engineering
http://www.joachim-breitner.de/blog/676-Talk_and_Article_on_Monads_for_Reverse_Engineeringhttp://www.joachim-breitner.de/blog/676-Talk_and_Article_on_Monads_for_Reverse_Engineering#commentsmail@joachim-breitner.de (Joachim Breitner)<p>In a recent project of mine, a <a href="http://github.com/entropia/tip-toi-reveng">tool to analyze and create files for the Ravensburger Tiptoi pen</a>, I used two interesting Monads with good results:</p>
<ul>
<li>A parser monad that, while parsing, remembers what part of the file were used for what and provides, for example, an annotated hex dump.</li>
<li>A binary writer monad that allows you to reference and write out offsets to positions in the file that are only determined “later” in the monad, using <a href="https://wiki.haskell.org/MonadFix">MonadFix</a>.</li>
</ul>
<p>As that’s quite neat, I write a <a href="http://funktionale-programmierung.de/2015/04/15/monaden-reverse-engineering.html">blog post</a> for the German blog funktionale-programmierung.de about it, and also held a <a href="http://www.meetup.com/The-Karlsruhe-Functional-Programmers-Meetup-Group/events/221493241/">talk at the Karlsruhe functional programmers group</a>. If you know some German, enjoy; if not, wait until I have a reason to hold the talk in English. (As a matter of fact, I did hold the talk in English, but only spontaneously, so the text is in German only so far.)</p>Wed, 15 Apr 2015 23:32:40 +0200An academic birthday present
http://www.joachim-breitner.de/blog/675-An_academic_birthday_present
http://www.joachim-breitner.de/blog/675-An_academic_birthday_presenthttp://www.joachim-breitner.de/blog/675-An_academic_birthday_present#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Yesterday, which happened to be my 30th birthday, a small package got delivered to my office: The printed <a href="http://www.springer.com/computer/swe/book/978-3-319-14674-4">proceedings</a> of last year's <a href="http://foswiki.cs.uu.nl/foswiki/TFP2014">“Trends in Functional Programming” conference</a>, where I published a <a href="http://link.springer.com/chapter/10.1007/978-3-319-14675-1_3">paper on Call Arity</a> (<a href="http://www.joachim-breitner.de/publications/CallArity-TFP.pdf">preprint</a>). Although I doubt the usefulness of printed proceedings, it was a nicely timed birthday present.</p>
<p>Looking at the rather short table of contents – only 8 papers, after 27 presented and 22 submitted – I thought that this might mean that, with some luck, I might have chances to get the “Best student paper award”, which I presumed to be announced at the next iteration of the conference.</p>
<p>For no particular reason I was leisurely browsing through the book, and started to read the <a href="http://www.springer.com/cda/content/document/cda_downloaddocument/9783319146744-p1.pdf">preface</a>. And what do I read there?</p>
<blockquote>
<p>Among the papers selected for these proceedings, two papers stood out. The award for Best Student Paper went to Joachim Breitner for his paper entitled Call Arity, and the award for Best Paper Overall went to Edwin Brady for his paper entitled Resource-dependent Algebraic Effects. Congratulations!</p>
</blockquote>
<p>Now, that is a real nice birthday present! Not sure if I even would have found out about it, had I not have thrown a quick glance at page V...</p>
<p>I hope that it is a good omen for my related <a href="http://www.joachim-breitner.de/publications/CallArity-ICFP2015-preprint.pdf">ICFP'15 submission</a>.</p>Sat, 28 Mar 2015 13:13:15 +0100DarcsWatch End-Of-Life’d
http://www.joachim-breitner.de/blog/672-DarcsWatch_End-Of-Life%E2%80%99d
http://www.joachim-breitner.de/blog/672-DarcsWatch_End-Of-Life%E2%80%99dhttp://www.joachim-breitner.de/blog/672-DarcsWatch_End-Of-Life%E2%80%99d#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Almost seven years ago, at a time when the “VCS wars” have not even properly started yet, GitHub was seven days old and most Haskell related software projects were using <a href="http://darcs.net/">Darcs</a> as their version control system of choice, when you submitted a patch, you simply ran <code>darcs send</code> and mail with your changes would be sent to the right address, e.g. the maintainer or a mailing list. This was almost as convenient as Pull Requests are on Github now, only that it was tricky to keep track of what was happening with the patch, and it would be easy to forget to follow up on it.</p>
<p>So back then I <a href="//www.joachim-breitner.de/blog/290-Announcing_DarcsWatch">announced DarcsWatch</a>: A service that you could CC in your patch submitting mail, which then would monitor the repository and tell you about the patches status, i.e. whether it was applied or obsoleted by another patch.</p>
<p>Since then, it quitely did its work without much hickups. But by now, a lot of projects moved away from Darcs, so I don’t really use it myself any more. Also, its Darcs patch parser does not like every submissions by a contemporary darcs, so it is becoming more and more unreliable. I asked around on the xmonad and darcs mailing lists if others were still using it, and noboy spoke up. Therefore, after seven years and 4660 monitored patches, I am officially ceasing to run DarcsWatch.</p>
<p>The code and data is still there, so if you believe this was a mistake, you can still speak up -- but be prepared to be asked to take over maintaining it.</p>
<p>I have a disklike for actually deleting data, so I’ll keep the static parts of <a href="http://darcswatch.nomeata.de/">DarcsWatch web page</a> in the current state running.</p>
<p>I’d like to thank the guys from <a href="http://www.spiny.org.uk/">spiny.org.uk</a> for hosting DarcsWatch on <a href="http://urchin.earth.li/">urching</a> for the last 5 years.</p>Wed, 25 Feb 2015 23:39:00 +0100ghc-heap-view for GHC 7.8
http://www.joachim-breitner.de/blog/662-ghc-heap-view_for_GHC_7_8
http://www.joachim-breitner.de/blog/662-ghc-heap-view_for_GHC_7_8http://www.joachim-breitner.de/blog/662-ghc-heap-view_for_GHC_7_8#commentsmail@joachim-breitner.de (Joachim Breitner)<p>Since the last release of <a href="http://hackage.haskell.org/package/ghc-heap-view">ghc-heap-view</a>, which was compatible with GHC-7.6, I got 8 requests for a GHC-7.8 compatible version. I started working on it in January, but got stuck and then kept putting it off.</p>
<p>Today, I got the ninths request, and I did not want to wait for the tenth, so I finally finished the work and you can use the new ghc-heap-view-0.5.2 with GHC-7.8.</p>
<p>I used this chance to migrate its source repository from Darcs to <a href="http://git.nomeata.de/?p=ghc-heap-view.git">git</a> (<a href="http://github.com/nomeata/ghc-heap-view">mirrored on GitHub</a>), so maybe this means that when 7.10 comes out, the requests to update it come with working patches :-). I also added a small test script so that travis can check it: <a href="https://travis-ci.org/nomeata/ghc-heap-view"><img src="https://travis-ci.org/nomeata/ghc-heap-view.svg?branch=master" alt="ghc-heap-view"/></a></p>
<p>I did not test it very thoroughly yet. In particular, I did not test whether <a href="http://hackage.haskell.org/package/ghc-vis">ghc-vis</a> works as expected.</p>
<p>I still think that the low-level interface that ghc-heap-view creates using custom Cmm code should move into GHC itself, so that it does not break that easily, but I still did not get around to propose a patch for that.</p>Tue, 07 Oct 2014 13:55:05 +0200