tag:blogger.com,1999:blog-38261647965643305902018-05-16T23:32:54.452+02:00The Most Fuun You Can HaveFor the augmentation of the complexity and intensity of the field of intelligent life.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-3826164796564330590.post-42994128962959271812008-11-07T11:38:00.003+02:002008-11-07T23:59:10.536+02:00Beautiful folding<pre><br />> {-# LANGUAGE ExistentialQuantification #-}<br /><br />> import Data.List (foldl')<br /></pre><br />If you're not a Haskeller, and were thus hoping to learn how to fold a shirt beautifully, I'm afraid you're out of luck. I don't know either.<br /><br />Much has been said about writing a Haskell function to calculate the mean of a list of numbers. For example, see Don Stewart's <a href="http://cgi.cse.unsw.edu.au/~dons/blog/2008/05/16">"Write Haskell as fast as C"</a>. Basically, one wants to write "nice, declarative" code like this:<br /><pre><br />> naiveMean :: Fractional a => [a] -> a<br />> naiveMean xs = sum xs / fromIntegral (length xs)<br /></pre><br />but if <code>xs</code> is large, <code>sum</code> will bring the whole thing into memory, but the garbage collector won't be able to collect it, since we still need it to calculate the length.<br /><br />The solution is to calculate both the sum and the length in one pass, and it's usually written something like this:<br /><pre><br />> uglyMean :: Fractional a => [a] -> a <br />> uglyMean xs = divide $ foldl' f (P 0 0) xs<br />> where <br />> f :: Num a => Pair a Int -> a -> Pair a Int<br />> f (P s l) x = P (s + x) (l + 1) <br />> divide (P x y) = x / fromIntegral y<br /></pre><br />where <code>P</code> is a strict pair constructor. This works, but where is the elegance, abstraction and modularity that Haskell is supposed to be famous for? Don's solution is even uglier (sorry, Don): not only does he write the reductor (our <code>f</code>) explicitly, but also the fold itself.<br /><br />What I hope to do here is to abstract this pattern away, by making "combinable folds". I only do <code>foldl'</code>, although <code>foldl1'</code> could be handy.<br /><br />To make folds combinable, we need to turn folds into data: a fold is a function (the reductor) with an initial value. To make folds more readily combinable, we add a post-processing function (here it is <code>divide</code>). Now that we have the post-processor, we don't need to look at the accumulator directly, so we make it existential. The type <code>Fold b c</code> is for folds overs lists of type <code>[b]</code>, with<br />results of type <code>c</code>.<br /><pre><br />> data Fold b c = forall a. F (a -> b -> a) a (a -> c)<br /></pre><br />We'll need a strict pair type, and I don't want to give my blog a dependency on the strict package, so I introduce my own:<br /><pre><br />> data Pair a b = P !a !b<br /></pre><br />Now that folds are data, we can start manipulating them. For example, we can<br />combine two folds to get a pair of results (we make the result an ordinary tuple for convenience, but use strict pairs for the accumulator to get the rightstrictness). The <code>(***)</code> defined here is like the one in <code>Control.Arrow</code>, but takes a strict pair as input. The reductor (<code>comb f g</code>) is basically <code>(first f) . (second g)</code> for strict pairs.<br /><pre><br />> both :: Fold b c -> Fold b c' -> Fold b (c, c')<br />> both (F f x c) (F g y c') = F (comb f g) (P x y) (c *** c')<br />> where<br />> comb f g (P a a') b = P (f a b) (g a' b)<br />> (***) f g (P x y) = (f x, g y)<br /></pre><br />Our next combinator simply adds an extra post-processor.<br /><pre><br />> after :: Fold b c -> (c -> c') -> Fold b c'<br />> after (F f x c) d = F f x (d . c)<br /></pre><br />The next one, bothWith, is a combination of both and after.<br /><pre><br />> bothWith :: (c -> c' -> d) -> Fold b c -> Fold b c' -> Fold b d<br />> bothWith combiner f1 f2 = after (both f1 f2) (uncurry combiner)<br /></pre><br />Now that we have tools to build folds, we want to actually fold them, so here is combinator <code>foldl'</code>:<br /><pre><br />> cfoldl' :: Fold b c -> [b] -> c<br />> cfoldl' (F f x c) = c . (foldl' f x)<br /></pre><br />Now lets see a few basic folds:<br /><pre><br />> sumF :: Num a => Fold a a<br />> sumF = F (+) 0 id<br /><br />> productF :: Num a => Fold a a<br />> productF = F (*) 1 id<br /><br />> lengthF :: Fold a Int<br />> lengthF = F (const . (+1)) 0 id<br /></pre><br />And, the moment we've all been waiting for, combining basic folds to get the mean of a list:<br /><pre><br />> meanF :: Fractional a => Fold a a<br />> meanF = bothWith (/) sumF (after lengthF fromIntegral)<br /><br />> mean :: Fractional a => [a] -> a<br />> mean = cfoldl' meanF<br /></pre><br />Pretty simple, eh? Perhaps not quite as pretty as naiveMean, but best of all, it doesn't eat your memory and kill your swap like naiveMean does.<br /><pre><br />> main = do<br />> let xs = [1..10000000]<br />> print $ mean xs<br /></pre><br />Compiling with GHC 6.8.2 and -O2, this runs in about 1.2 seconds (on my three-year-old laptop) and uses less than a meg of memory. GHC generates the same code for mean and uglyMean. [Originally <code>uglyMean</code> was slightly faster, but this was because of type defaulting: the result of <code>lengthF</code> defaulted to <code>Integer</code>]<br /><br />One thing remains. What do Haskellers do when there's a pretty way and a fast way (or at least a way that's more susceptible to optimisation) to do the same thing? We write rewrite rules. So we'd like to convert sum, length, etc. into combinable folds, and then combine them. Something like this:<br /><pre><br />> {-<br />> {-# RULES<br />> "sum/sumF" sum = cfoldl' sumF<br />> "product/productF" product = cfoldl' productF<br />> "length/lengthF" length = cfoldl' lengthF<br />> "multi-cfoldl'" forall c f g xs. c (cfoldl' f xs) (cfoldl' g xs) <br />> = cfoldl' (bothWith c f g) xs<br />> #-}<br />> -}<br /></pre><br />So why are these commented out? Unfortunately, GHC doesn't like the<br />all-important "multi-foldl'" rule: it doesn't have a named function at its head (it has the variable c). GHC doesn't allow rules of this form, presumably for efficiency and simplicity in the compiler.<br /><br />So unfortunately, we can't go back to writing pretty-but-naive code, but with these combinators at our disposal, we are at least saved from writing *ugly* code.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com9tag:blogger.com,1999:blog-3826164796564330590.post-62401615827966277982008-03-10T19:46:00.000+02:002008-03-10T20:17:12.222+02:00Mathematics for Arithmeticians: Pons asinorumIn today's post, I will show Pappus's proof of the so-called <em>Pons asinorum</em> or Bridge of Asses. The theorem is given this name because it is the first difficult theorem in Euclid's <em>Elements</em>. The theorem states that the base angles of an isosceles triangle are equal.<br /><br />Consider triangle ABC, with AB = BC. Now we want to prove that angle A is equal to angle C. One useful trick in geometry for proving things equal is to use congruence of triangles, but we only have <em>one</em> triangle.<br /><br />Or do we? Pappus' trick is to look at one triangle two ways: ABC and its reflection CBA. AB = CB (by our starting assumption), BA = BC (by the same assumption), and AC = CA (they're the same line). So ABC ≡ CBA (all three corresponding sides are equal, so they're congruent). Since they're congruent, the corresponding angles are equal: angle A equals angle B.<br /><br />That's it. This trick allows us to prove the theorem in just a few steps.<br /><br />Why do I think this elegant? By looking at one thing in two ways, we learnt something new, and remarkably quickly. And the great thing is that you can use this trick again, to prove the converse using angle-side-angle congruence. And a trick you can use more than once is a technique.<br /><br />If you followed this, well done. You have crossed the Bridge of Asses.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com0tag:blogger.com,1999:blog-3826164796564330590.post-88513460400236770652008-03-03T19:10:00.005+02:002008-03-03T20:58:09.778+02:00Mathematics for Arithmeticians: Prime NumbersI've decided to stop calling myself a computer science student — I got tired of being <em>the computer guy</em> — and go for mathematics instead.<br /><br />People used to ask me to fix their computers. Now they ask me to calculate the tip and divide the bill when we go to restaurants, too.<br /><br />Yeah, so people don't know what mathematics is any better than they know what computer science is. <br /><br />Maths is not arithmetic (though arithmetic sometimes helps us do maths). Maths is not a set of facts you don't understand handed down from on high for you to remember. It's a world to explore and understand. To enjoy it, you'll want to explore yourself, but I'm going to show you some of the sights. Hopefully, a bit of high-school vocabulary and a bit of thought should be enough to understand this. <sup><a name="body-source"><a href="#foot-source">*</a></a></sup><br /><br />As one of my lecturers pointed out the other day, one of the reasons the natural numbers (whole, positive numbers) are interesting is because they have two kinds of structure: additive and multiplicative. The building block of the additive structure is one: we can make any number by taking one, adding one, adding one again, etc.<br /><br />But the multiplicative structure is a little more intricate. The building blocks are called "prime": the numbers you can't make by multiplying other numbers together. I'm sure you know them. 2, 3, 5, 7, 11, and so on.<br /><br />And so on? Does that mean I'm too lazy to list them all. Nope... there are infinitely many primes. How do I know? I have a proof.<br /><br />First off, what does it mean for there to be infinitely many primes? Clearly, it means for any prime, there is another one bigger than it. So how can we show that there is a prime bigger than <var>p</var>?<br /><br />Take all the primes up to <var>p</var>, multiply them together, and add one: 2×3×5×...<var>p</var> + 1. This number isn't divisible by 2 (since the number is two times something plus 1, when you divide it by two you get a remainder of 1). Similarly, it isn't divisible by 3, 5, or any other prime up to <var>p</var>.<br /><br />So either 2×3×5×...<var>p</var> + 1 is prime, or there is some prime number bigger than <var>p</var> which divides it.<br /><br />So <var>p</var> is not the largest prime. But this argument works for any <var>p</var>, so there is <em>no</em> largest prime.<br /><br />This proof is due to Euclid. We proceeded from an obvious starting point, by obvious steps (if any of them were not obvious, leave a comment and I'll explain in further detail), to a non-obvious, interesting conclusion.<br /><br />I hope you think this is as beautiful as I do.<br /><br /><hr /><br /><br /><a name="foot-source"><a href="#body-source">*</a></a> The things I plan to present in this series are basically the subset of things that I've been thinking about and discussing with my friends which I can explain to my girlfriend, who is interested in maths but has never studied it beyond school.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com6tag:blogger.com,1999:blog-3826164796564330590.post-8564792990800909922008-01-22T13:26:00.000+02:002008-01-22T14:54:54.552+02:00Unmonad Tutorial: IO in Haskell without understanding monadsForget monads!<br /><br />These days, I hear a lot of "what kind of language makes you learn category theory to do IO" and "monads are a kludge to allow IO in a pure language."<br /><br />Both of these ideas are rubbish. You can do IO without understanding monads, and monads aren't a way of doing IO. The usual way to demonstrate this is to write yet another monad tutorial. But I'm bored of monad tutorials: half of them don't make sense, and anyway, I just want to do some frickin' IO.<br /><br />It's pretty simple. Haskell introduces a datatype for IO actions, and a DSL for creating them. The fact that <code>IO</code> is an instance of the <code>Monad</code> typeclass is irrelevant for our purposes. I just want to do some frickin' IO.<br /><br />The DSL is simple: <strong><code>do</code></strong> introduces an IO action. IO actions are formatted either as brace-enclosed, semicolon-delimited (like C) or indented, newline-delimited statements (like Python). Each statement is one of the following:<br /><ul><br /><li><code><strong>let</strong> <var>n</var> = <var>v</var></code> binds <code><var>n</var></code> to the value <code><var>v</var></code>.</li><br /><br /><li><code><var>n</var> <strong><-</strong> <var>a</var></code> executes the action <code><var>a</var></code> and binds the name <code><var>n</var></code> to the result.</li><br /><br /><li><code><strong><var>a</var></strong></code>, on its own, executes the action <code><var>a</var></code>.</li><br /></ul><br />This is all rather similar to an imperative language, except that two types of assignment are distinguished.<br /><br />The result of running your newly constructed action is the result of the last action in your <code>do</code> block. Which leaves just one more thing you'll need <code>return</code>. This is not like the return of other languages: it's not a flow control statement. <code>return <var>x</var></code> is an IO action that does nothing but yield <code><var>x</var></code> when executed.<br /><br />Notice that the <code>let <var>n</var> = <var>v</var></code> form is actually unneeded: it is equivalent to <code><var>n</var> <- return <var>v</var></code>. So there's really only one type of assignment, if you prefer to look at it that way.<br /><br />You may be wondering how you pass arguments to an IO action. You don't. You make a function which takes arguments and returns an IO action.<br /><br />As a short example, I'll write a program that reads in some integers, and outputs a running total.<br /><br /><code>totalLoop</code> takes the old total, and produces an IO action which reads a line from standard input, converts it to an integer, prints the total, and then runs itself with the new total. It loops forever, so we give it the return type <code>()</code>, the empty tuple, which is used like <code>void</code> in Haskell.<br /><br /><pre><br />> totalLoop :: Integer -> IO ()<br />> totalLoop oldTotal =<br />> do<br />> input <- getLine -- getLine :: IO String<br />> let number = read input -- read :: String -> Integer<br />> let newTotal = oldTotal + number<br />> print newTotal -- print :: Integer -> IO ()<br />> totalLoop newTotal<br /></pre><br /><br /><code>main</code> simply runs <code>totalLoop</code> with a zero total.<br /><br /><pre><br />> main :: IO ()<br />> main =<br />> do<br />> totalLoop 0<br /></pre><br /><br />And there you have it: an IO-performing (if uninteresting) Haskell program, without any understanding of what monads are.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com0tag:blogger.com,1999:blog-3826164796564330590.post-65174764667638821332008-01-18T23:26:00.000+02:002008-01-19T00:06:04.300+02:00First player wins SuperghostInspired by the XKCD's <a href="http://blag.xkcd.com/2007/12/31/ghost/">blag post on the solution to Ghost</a>, I first verified his results, and then moved onto the somewhat harder task of solving Ghost's wicked step-sister, Superghost.<br /><br />Briefly, the rules of Superghost: the first player names a letter; then, each player in turn either adds a letter to the beginning ("conses" a letter) or to the end ("snocs" a letter; the words "cons" and "snoc" are not game terminology, but functional-programming jargon). The first player to create a string of letters which is not part of a real word, or completes a real word, loses. I consider only the two-player version.<br /><br />The solver is written in Haskell, and uses the Ubuntu British English word list. Only words with four or more letters are considered. Words containing capital or accented letters are ignored.<br /><br />The program took about 22.5 seconds to find the solution: The first player wins, by playing <em>a, i, o, s,</em> or <em>v</em>.<br /><br />The winning responses for the second player:<br /><pre><br />('a',[])<br />('b',[Snoc 'w'])<br />('c',[Cons 'g',Cons 'w',Snoc 'd',Snoc 'q'])<br />('d',[Cons 'c',Cons 'f',Cons 'g',Snoc 'w'])<br />('e',[Snoc 'r'])<br />('f',[Cons 'f',Cons 'h',Cons 'l',Cons 'x',Snoc 'd',Snoc 'f',Snoc 'g',Snoc 'n',Snoc 'p',Snoc 'w'])<br />('g',[Cons 'f',Cons 'h',Cons 'l',Cons 'x',Snoc 'c',Snoc 'd',Snoc 'j',Snoc 'm',Snoc 'w',Snoc 'z'])<br />('h',[Cons 'm',Cons 'n',Cons 'x',Snoc 'f',Snoc 'g',Snoc 'k',Snoc 'q'])<br />('i',[])<br />('j',[Cons 'g',Cons 'k',Cons 'p',Cons 'r',Cons 'u'])<br />('k',[Cons 'h',Cons 'k',Cons 't',Cons 'w',Cons 'y',Snoc 'j',Snoc 'k'])<br />('l',[Cons 'w',Cons 'x',Snoc 'f',Snoc 'g'])<br />('m',[Cons 'g',Snoc 'h'])<br />('n',[Cons 'f',Cons 'x',Snoc 'h',Snoc 'w',Snoc 'x'])<br />('o',[])<br />('p',[Cons 'f',Snoc 'j'])<br />('q',[Cons 'c',Cons 'h',Cons 'x'])<br />('r',[Cons 'e',Cons 'r',Snoc 'j',Snoc 'r'])<br />('s',[])<br />('t',[Snoc 'k'])<br />('u',[Snoc 'j'])<br />('v',[])<br />('w',[Cons 'b',Cons 'd',Cons 'f',Cons 'g',Cons 'n',Cons 'w',Snoc 'c',Snoc 'k',Snoc 'l',Snoc 'w',Snoc 'y'])<br />('x',[Cons 'n',Snoc 'f',Snoc 'g',Snoc 'h',Snoc 'l',Snoc 'n',Snoc 'q'])<br />('y',[Cons 'w',Snoc 'k'])<br />('z',[Cons 'g'])<br /></pre><br /><br />Byorgey wanted code... he gets code. Sorry about the lack of comments, but this is a for-fun hack.<br /><pre><br />module Main where<br /><br />import qualified Data.Set as S<br />import qualified Data.Map as M<br />import qualified Data.List as L<br />import Data.Maybe (fromMaybe)<br />import Control.Applicative<br /><br />type SuperghostDict = M.Map String (S.Set String)<br /><br />data Play = Cons Char | Snoc Char deriving (Show, Eq, Ord)<br /><br />getWords :: IO [String]<br />getWords = filter (all (`elem` ['a'..'z'])) <$><br /> lines <$><br /> readFile "/usr/share/dict/words"<br /><br />makeDict :: [String] -> SuperghostDict<br />makeDict words = M.unionWith S.union<br /> (M.fromListWith S.union $<br /> concatMap (\word -> let tails = L.tails word in<br /> zip (tail tails) $ map S.singleton tails)<br /> words)<br /> (M.fromAscList $ map (\x -> (x, S.empty)) $ words)<br /><br />wordsEnding :: String -> SuperghostDict -> S.Set String<br />wordsEnding word dict = (fromMaybe S.empty $ M.lookup word dict)<br /><br />wordsStarting :: String -> SuperghostDict -> S.Set String<br />wordsStarting word dict = S.fromAscList $<br /> (takeWhile (word `L.isPrefixOf`) $ map fst $<br /> M.toAscList $ snd $ M.split word dict)<br /><br />wordsMiddling :: String -> SuperghostDict -> S.Set String<br />wordsMiddling word dict = (foldr S.union S.empty<br /> (map snd $ takeWhile ((word `L.isPrefixOf`) . fst) $<br /> M.toAscList $ snd $ M.split word dict))<br /><br />wordsWith :: String -> SuperghostDict -> S.Set String<br />wordsWith word dict = (wordsEnding word dict) `S.union`<br /> (wordsStarting word dict) `S.union`<br /> (wordsMiddling word dict)<br /><br />plays :: String -> SuperghostDict -> S.Set Play<br />plays word dict = (S.map (\ w -> (Snoc $ w !! (length word))) $<br /> wordsStarting word dict)<br /> `S.union` (S.map (\ w -> Cons $ head w)<br /> $ wordsEnding word dict)<br /> `S.union` (S.map (\ w -> Cons $ head w)<br /> $ wordsMiddling word dict)<br /><br />apply :: String -> Play -> String<br />apply word (Snoc c) = word ++ [c]<br />apply word (Cons c) = c:word<br /><br />winnable :: SuperghostDict -> String -> Bool<br />winnable dict word = let moves = S.toList $ plays word dict in<br /> if null moves then<br /> True<br /> else<br /> any (not . (winnable dict) . (apply word)) moves<br /><br />winningPlays :: SuperghostDict -> String -> [Play]<br />winningPlays dict word = let moves = S.toList $ plays word dict in<br /> filter (not . (winnable dict) . (apply word)) moves<br /><br />forever :: (Monad m) => m a -> m ()<br />forever x = x >> forever x<br /><br />main = do<br /> dict <- makeDict <$> filter ((> 3) . length) <$> getWords<br /> print $ winningPlays dict ""<br /></pre>Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com0tag:blogger.com,1999:blog-3826164796564330590.post-29088515186802060772007-10-24T15:06:00.000+02:002007-10-24T15:33:29.752+02:00An update: results and researchI have seen the ICFP, and it is full of funky symbols. Yes, we won a prize; two of the twelve of us headed of to Freiburg-im-Breisgau; and we came second, beaten by Team Smartass of Google. Interestingly, of the four contestants in Freiburg to collect prizes, three were South African (myself and <a href='http://marco-za.blogspot.com/2007/10/icfp-how-we-came-2nd.html'>Marco</a> from the United Coding Team, as well as Daniel Wright of Team Smartass).<br /><br />A few months ago I posted an translation of Wolfram's (2, 3) Turing Machine into Fuun DNA. What I called "an open problem of Wolfram" is now closed. Today <a href='http://blog.wolfram.com/2007/10/the_prize_is_won_the_simplest.html'>Wolfram announced</a> that this machine has been proven universal by Alex Smith. Since there is known to be no (2, 2) UTM, Wolfram and Smith's machine is the smallest Universal Turing Machine.<br /><br />Somewhat related to Wolfram and Smith, but *very* related to programmable Fuun DNA: <a href='http://www.springerlink.com/content/uxuc20mnurg4qjug/'>programmable terrestial DNA</a> — Programmed Mutagenesis Is a Universal Model of Computation by Khodor and Gifford. Perhaps Endo isn't as alien as we thought?Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com2tag:blogger.com,1999:blog-3826164796564330590.post-73342262603217859562007-09-19T17:24:00.000+02:002007-09-19T22:55:23.194+02:00Haskelling the SACO 1<span style="font-style:italic; font-size:small;">These blog entries is to record my early adventures in Haskell, to advertise the SACO, and show off the awesomeness of Literal Haskell (which means that this entire post can be pasted into a text file and compiled) by documenting my solutions to programming contest problems.<br /></span><br /><br />I've finally decided to learn Haskell. For about the third time.<br /><br />But this time I'm actually doing it.<br /><br />Since we've just hosted another successful <a href="http://olympiad.cs.uct.ac.za/old/">South African Computer Olympiad</a><sup><a name="fn-body-1" href="#fn-1">[1]</a></sup>, I decided to code some Haskell solutions. Looking through the problems, I decided on Living Dead Parrots: I didn't code a check solution before the contest, so it wouldn't be too boring, but it was easy enough that I would spend more time learning the language than figuring out the algorithm. Most importantly, it was an interactive problem<sup><a name="fn-body-2" href="#fn-2">[2]</a></sup>, meaning I would be brought face-to-face with the IO monad, a fearful prospect for the novice Haskeller.<br /><br />Well, it wasn't as scary as I'd feared. By no means.<br /><br />In short, the problem we're solving is this: the evaluator has an array of <var>N</var> booleans. You can ask it for the number of true values between two indices (inclusive, base one). Less than a hundredth of the booleans are true. There is a limit on the number of queries you can make, but we ignore it, since it is always larger than the number needed by the correct algorithm.<br /><br />This solution scores 100% (within the C++ time limit, when compiled with GHC), but is probably not the best Haskell ever written. I'd appreciate any advice you can give for improvements. That's why I'm posting, after all.<br /><br />First, the preliminaries:<br /><br /><pre><br />> module Main<br />> where<br />><br />> import System.IO<br />><br />> rInt :: String -> Int<br />> rInt = read<br />><br />> flush :: IO ()<br />> flush = hFlush stdout<br /></pre><br /><br />Next, the function to query the evaluator. We output "Q <var>a</var> <var>b</var>", and read in an integer. The answer is obviously wrapped in the IO monad.<br /><br /><pre><br />> query :: Int -> Int -> IO Int<br />> query a b = do putStrLn ("Q " ++ (show a) ++ " " ++ (show b))<br />> flush<br />> answer <- getLine<br />> return $ rInt answer<br /></pre><br /><br />I'm not particularly proud of this function, which wraps a value in the IO monad. If it's the right thing to do, there's a library function for it; if it's the wrong thing to do, I shouldn't do it. If you know which it is, leave a comment.<br /><br /><pre><br />> coerceIO :: a -> IO a<br />> coerceIO x = do return x<br /></pre><br /><br />Here comes the meaty part. Search takes a range, and the number of parrots (oh, yes, those booleans represent whether a parrot in a certain cage is pining for the fjords or has kicked the bucket) in that range, and determines where those parrots are.<br /><br /><pre><br />> search :: Int -> Int -> Int -> IO [Bool]<br /></pre><br /><br />There are three cases. The first is that the range contains no parrots.<br /><br /><pre><br />> search start end 0 = coerceIO $ take (end-start+1) (repeat False)<br /></pre><br /><br />The next case is that the range contains only one element, then we have found the location of a living parrot.<br /><br /><pre><br />> search start end 1 | start == end = coerceIO [True]<br /></pre><br /><br />The interesting case is the remaining one, where we divide the list into two, and recurse.<br /><br /><pre><br />> search start end numParrots = let middle = (end+start) `div` 2<br />> in do leftNum <- query start middle<br />> left <- search start middle leftNum<br />> right <- search (middle+1) end (numParrots-leftNum)<br />> return (left ++ right)<br /></pre><br /><br />All that remains is <code>main</code>, which contains my most suspicious use of <code>coerceIO</code>, to bind purely functional variables in a monad: I haven't figured out how to use <code>let</code> in a <code>do</code>.<br /><br />It first reads a line containing two integers: the size of the parrot array, and the number of questions. We ignore the latter. We then find the number of live parrots in the array, and begin the search. The output format is "A 0 0 0 0 1 0 1 0 1 ...".<br /><br /><pre><br />> main :: IO ()<br />> main = do line <- getLine<br />> n <- coerceIO $ rInt $ head $ words line<br />> numParrots <- query 1 n<br />> parrots <- search 1 n numParrots<br />> putStrLn $ "A " ++ (unwords $ map (\x -> if x then "1" else "0") parrots)<br />> return ()<br /></pre><br /><br />Notes on Haskell syntax, for non-Haskellers: <code>f $ x</code> is the same as <code>f x</code>, except that it binds more loosely. Its purpose is mostly to eliminate lots of irritating superfluous parentheses. <code>(\x -> y)</code> is an anonymous function mapping <code>x</code> to <code>y</code> <br /><br /><sup><a name="fn-1" href="#fn-body-1">[1]</a></sup>We now run a parallel contest online: same problems, but open to anyone. You should check it out this time next year. We might also be running the contests from the training camps online (training camps happen about three times a year, starting in February). Unfortunately, Haskell is not one of the supported languages, but after the contests you can download the evaluator programs and test data to score solutions in any language.<br /><br /><sup><a name="fn-1" href="#fn-body-1">[2]</a></sup>In the SACO, interactive problem solutions communicate through pipes with an evaluator, rather than reading an input file and writing an output file. This allows problems where access to the full dataset is unnecessary, and is either not allowed or too big to be read completely within the time limit.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com7tag:blogger.com,1999:blog-3826164796564330590.post-26088876928776108262007-08-29T21:31:00.000+02:002007-08-30T01:17:53.784+02:00Mr Turing, meet EndoFrom the moment we saw what Endo's DNA was doing as we ran it, every ICFP contestant (at least, those who got that far) knew in their hearts that Fuun DNA is Turing complete. But I am a mathematician! And mathematicians need proof.<br /><br />Mr Turing, I'd like you to meet Endo:<br /><br /><pre>IIPIFFPCPPPIICIIPIFFPCPPFIICIIPIFFPCPPPIICIICIFPIC<br />PIFPCPIFPICPIICFIFFFFIFCIPPFIFCCCIFIFCPFIFCFFIFIFC<br />PCIFIFCPFIFFIFIFFCIIPIFFPCPFCIICICICPCPFFPCPCPFICP<br />CPFPPCPPCIICIFPPICPPCPFFFFPCPFICPCPFPPCPPCFICPCPFI<br />CIICIIPIFFPCPFCIICICICPCPFFPCPCPFICPCPFPIIPIFFPCPF<br />ICIICIIPIFFPCPPCIICIICIFPPICPPCPFFIFPCPPCPFPIFPICP<br />FICPCPFICIICIIPIFFPCPFCIICICICPCPFFFICPCPFICPCPFPI<br />IPIFFPCPPCIICPCPPFIICIFPPICPPCPFFFCPCPFICPCPFPPCPC<br />PFICIFPCPPCPPFIICIIPIFFPCPFCIICICICPCPFFFICPCPFICP<br />CPFPIIPIFFPCPPCIICIIPIFFPCPFICIICIICIFPPICPPCPFFIF<br />PICPPCPFPPCPCPFICIFPCPIICIIPIFFPCPFCIICICICPCPFFFP<br />PCPFICPCPFPIIPIFFPCPPCIICPCPPFIICIFPPICICPCPFFFCPC<br />PFICPCPFPFCPCPFICIFPCPPCPPFIICIIPIFFPCPFCIICICICPC<br />PFFFPPCPFICPCPFPIIPIFFPCPPCIICIIPIFFPCPFICIICIICIF<br />PPICICPCPFFIFPICPPCPFPFCPCPFICIFPCPIICIIPIFFPCPFCI<br />ICICICPCPFFFFPCPFICPCPFPIIPIFFPCPPCIICPCPPFIICIFPP<br />ICICPCPFFFCPCPFICPCPFPFCPCPFICIFPCPPCPPFIICIIPIFFP<br />CPFCIICICICPCPFFFFPCPFICPCPFPIIPIFFPCPPCIICIIPIFFP<br />CPFICIICIICIFPPICICPCPFFIFPICPPCPFPFCPCPFICIFPCPII<br />CIIPIFFPCPFCIICICICPCPFFFCPCPFICPCPFPPCPPCIICIFPPI<br />CICPCPFFFFPCPFICPCPFPPCPPCFFPCPFICIICIIPIFFPCPFCII<br />CICICPCPFFFCPCPFICPCPFPIIPIFFPCPFICIICIIPIFFPCPPCI<br />ICIICIFPPICICPCPFFIFPCPPCPFPIFPICPFFPCPFICIICIIPIF<br />FPCPFCIICICPPCPFFPCPCPFICPCPFPPCPPCIICIFPPICPPCPFF<br />FFPCPFICPCPFPPCPPCFPPCPFICIICIIPIFFPCPFCIICICPPCPF<br />FPCPCPFICPCPFPIIPIFFPCPFICIICIIPIFFPCPPCIICIICIFPP<br />ICPPCPFFIFPCPPCPFPIFPICPFPPCPFICIICIIPIFFPCPFCIICI<br />CPPCPFFFICPCPFICPCPFPIIPIFFPCPPCIICPCPPFIICIFPPICP<br />PCPFFFCPCPFICPCPFPPCPCPFICIFPCPPCPPFIICIIPIFFPCPFC<br />IICICPPCPFFFICPCPFICPCPFPIIPIFFPCPPCIICIIPIFFPCPFI<br />CIICIICIFPPICPPCPFFIFPICPPCPFPPCPCPFICIFPCPIICIIPI<br />FFPCPFCIICICPPCPFFFPPCPFICPCPFPIIPIFFPCPPCIICPCPPF<br />IICIFPPICICPCPFFFCPCPFICPCPFPPCPCPFICIFPCPPCPPFIIC<br />IIPIFFPCPFCIICICPPCPFFFPPCPFICPCPFPIIPIFFPCPPCIICI<br />IPIFFPCPFICIICIICIFPPICICPCPFFIFPICPPCPFPPCPCPFICI<br />FPCPIICIIPIFFPCPFCIICICPPCPFFFFPCPFICPCPFPIIPIFFPC<br />PPCIICPCPPFIICIFPPICICPCPFFFCPCPFICPCPFPFCPCPFICIF<br />PCPPCPPFIICIIPIFFPCPFCIICICPPCPFFFFPCPFICPCPFPIIPI<br />FFPCPPCIICIIPIFFPCPFICIICIICIFPPICICPCPFFIFPICPPCP<br />FPFCPCPFICIFPCPIICIIPIFFPCPFCIICICPPCPFFFCPCPFICPC<br />PFPPCPPCIICIFPPICICPCPFFFFPCPFICPCPFPPCPPCFICPCPFI<br />CIICIIPIFFPCPFCIICICPPCPFFFCPCPFICPCPFPIIPIFFPCPFI<br />CIICIIPIFFPCPPCIICIICIFPPICICPCPFFIFPCPPCPFPIFPICP<br />FICPCPFICIICIIPIFFPCPPPIICIIPIFFPCPPFIICIIPIFFPCPP<br />PIICIICIFPICPIFPCPIFPICPIICFIFFF<br /></pre><br /><br />I'm sure my (three, I think) regular readers have long ago worked out what I had up my sleeve, but this is it. Credit is due more to Cook and Wolfram than myself, and of course Endo and Turing, most of all.<br /><br />I realise that Jeuring, et al. have probably had a proof of this fact for several months, but I believe I am the first to make it public.<br /><br />To see this in action, configure your "build" program to output the current DNA at each iteration. The actual Turing machine data looks like this (it is surrounded front and back by the mechanics of the maching):<br /><br />"PPPCI $State PPPCC $Symbol PPPCP PPPCF $LeftStack PPPFI $RightStack PPPFC"<br /><br />$State is either "PP" (up) or "PF" (down). $Symbol is the symbol currently "under the head"; the symbols are "CI", "CC", "CF", "CP" and "FI", from white to black (note that I read NKS online, so I don't know what the colours are in the original). $LeftStack and $RightStack are lists of symbols delimited by "PPPCP", both starting with the tape cell nearest the head.<br /><br />My previous Turing machines had a similar structure, but used "markers" other than "PPPxx".<br /><br />EDIT: I have changed "FIFxx" for the markers, since strings of P's behave particularly badly in the face of quoting.<br /><br />I'll leave the rest to you to work out.<br /><br />Now... can we write a compiler before the organisers release theirs? I'm in the middle of a whole bunch of projects and tests, as well as practising for ACM ICPC, but I'd love to contribute if somebody else is prepared to lead for a bit.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com5tag:blogger.com,1999:blog-3826164796564330590.post-46261194841392737102007-08-26T22:47:00.000+02:002007-08-26T23:42:03.829+02:00On an open problem of WolframI have something to admit. Something rather shameful. <em>I never learnt Fuun during the contest.</em> After all, I was a late arrival to a team with a man we call Bruce Almighty, after whom the Bruce-First Search is named. Although I had a vague understanding of the low-level details, my contributions were mostly at a higher level.<br /><br />So I'm only really learning the details now, as I don my tin-foil hat and prepare for a Fuun-filled future. When I saw Jochen's ingenious 55-character junk generator, I had only an inkling of how it worked until I whipped out my spec booklet and a pencil. Jochen's string shows just how incredibly rich Fuun DNA is. And also that Jochen is a brilliant DNA hacker.<br /><br />I will now, finally, progress to my point. Last week, I left you with an SHA-1 "essence" of a result. In truth, it is more of a question than a result. It is suspected by some that the following DNA sequence has a truly awe-inspiring property: that the genetic program of any being can be emulated by this sequence of Fuun genes. Is this the case? A cash prize is offered for a proof of the affirmative.<br /><br /><pre>IIPIFFCFPPPIICIIPIFFCFPPFIICIIPIFFCFPPPIICIICIFPIC<br />PIFPCPIFPICPIICICFFFICFCIPFICFCCCCICFCPICFCFICFFII<br />CFFCIIPIFFCFPFCIICICPCFPFFFPCFPFICCFPFPCFPPCIICIFP<br />PICPCFPFFFFCFPFICCFPFPCFPPCFCCFPFICIICIIPIFFCFPFCI<br />ICICPCFPFFFPCFPFICCFPFPIIPIFFCFPFICIICIIPIFFCFPPCI<br />ICIICIFPPICPCFPFFIFPCPCFPFPIFPICPFCCFPFICIICIIPIFF<br />CFPFCIICICPCFPFFFCCFPFICCFPFPCFPPCIICIFPPICPCFPFFF<br />FCFPFICCFPFPCFPPCFPCFPFICIICIIPIFFCFPFCIICICPCFPFF<br />FCCFPFICCFPFPIIPIFFCFPFICIICIIPIFFCFPPCIICIICIFPPI<br />CPCFPFFIFPCPCFPFPIFPICPFPCFPFICIICIIPIFFCFPFCIICIC<br />PCFPFFFFCFPFICCFPFPIIPIFFCFPPCIICCFPPFIICIFPPICICC<br />FPFFFFCFPFICCFPFPFCCFPFICIFPCPCFPPFIICIIPIFFCFPFCI<br />ICICPCFPFFFFCFPFICCFPFPIIPIFFCFPPCIICIIPIFFCFPFICI<br />ICIICIFPPICICCFPFFIFPICPCFPFPFCCFPFICIFPCPIICIIPIF<br />FCFPFCIICICICCFPFFFPCFPFICCFPFPIIPIFFCFPPCIICCFPPF<br />IICIFPPICPCFPFFFFCFPFICCFPFPFFCFPFICIFPCPCFPPFIICI<br />IPIFFCFPFCIICICICCFPFFFPCFPFICCFPFPIIPIFFCFPPCIICI<br />IPIFFCFPFICIICIICIFPPICPCFPFFIFPICPCFPFPFFCFPFICIF<br />PCPIICIIPIFFCFPFCIICICICCFPFFFCCFPFICCFPFPIIPIFFCF<br />PPCIICCFPPFIICIFPPICICCFPFFFFCFPFICCFPFPFPCFPFICIF<br />PCPCFPPFIICIIPIFFCFPFCIICICICCFPFFFCCFPFICCFPFPIIP<br />IFFCFPPCIICIIPIFFCFPFICIICIICIFPPICICCFPFFIFPICPCF<br />PFPFPCFPFICIFPCPIICIIPIFFCFPFCIICICICCFPFFFFCFPFIC<br />CFPFPCFPPCIICIFPPICPCFPFFFFCFPFICCFPFPCFPPCFPCFPFI<br />CIICIIPIFFCFPFCIICICICCFPFFFFCFPFICCFPFPIIPIFFCFPF<br />ICIICIIPIFFCFPPCIICIICIFPPICPCFPFFIFPCPCFPFPIFPICP<br />FPCFPFICIICIIPIFFCFPPPIICIIPIFFCFPPFIICIIPIFFCFPPP<br />IICIICIFPICPIFPCPIFPICPIICICFFF</pre>Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com15tag:blogger.com,1999:blog-3826164796564330590.post-10629520588420263702007-08-23T16:51:00.000+02:002007-08-24T22:59:05.343+02:00Investigating Endo: Junk DNAMy friend Marco has <a href="http://marco-za.blogspot.com/search/label/icfp">blogged</a> about my team's experience in the ICFP, but since the contest, I've been investigating Endo's DNA. <a href="http://johanjeuring.blogspot.com/">Johann Jeuring</a> is slowly revealing some interesting facts, but as we know, he was kidnapped by Fuun invaders, and so we can't really trust what he tells us.<br /><br />I've discovered some truly remarkable properties of Fuun DNA, the proof of which this blog is wide enough to contain. Unfortunately Earth's internet has already been infiltrated by Fuun agents, as attested by their subversion of the ICFP itself.<br /><br />I will, however, reveal a single DNA sequence, which may prove useful in the defense against Fuun invaders, should they further threaten our planet. When "executed" it generates large amounts of "<a href="http://en.wikipedia.org/wiki/Junk_DNA">junk DNA</a>". JB and HM indicate that in generates on the order of 10<sup>865</sup> acids in about 10<sup>1730</sup> iterations before destroying itself, but of course our gene simulators would take many years to confirm this.<br /><br />Anyone who discovers more about this sequence or others related to it should post them on this blog, so that we may broaden our knowledge of our universe's lifeforms, and begin to coordinate anti-Fuun defense, should it be necessary.<br /><br /><pre>IIPIFFCFPPPIICIIPIFFCFPPFIICIIPIFFCFPPPIICIICIFPIC<br />PIFPCPIFPICPIICICFFFICFCIP<b>I</b>ICFCCCCICFCPICFCFICFFII<br />CFFCIIPIFFCFPFCIICICCCFPFFFFCFPFICCFPFPIIPIFFCFPPC<br />IICCFPPFIICIFPPICFCFPFFFFCFPFICCFPFPFCCFPFICIFPCPC<br />FPPFIICIIPIFFCFPFCIICICCCFPFFFFCFPFICCFPFPIIPIFFCF<br />PPCIICIIPIFFCFPFICIICIICIFPPICFCFPFFIFPICPCFPFPFCC<br />FPFICIFPCPIICIIPIFFCFPFCIICICCCFPFFFCCFPFICCFPFPCF<br />PPCIICIFPPPFCFPFFFFCFPFICCFPFPCFPPCFFCFPFICIICIIPI<br />FFCFPFCIICICCCFPFFFCCFPFICCFPFPIIPIFFCFPFICIICIIPI<br />FFCFPPCIICIICIFPPPFCFPFFIFPCPCFPFPIFPICPFFCFPFICII<br />CIIPIFFCFPFCIICICFCFPFFFFCFPFICCFPFPIIPIFFCFPPCIIC<br />CFPPFIICIFPPICPCFPFFFFCFPFICCFPFPFFCFPFICIFPCPCFPP<br />FIICIIPIFFCFPFCIICICFCFPFFFFCFPFICCFPFPIIPIFFCFPPC<br />IICIIPIFFCFPFICIICIICIFPPICPCFPFFIFPICPCFPFPFFCFPF<br />ICIFPCPIICIIPIFFCFPFCIICICFCFPFFFCCFPFICCFPFPIIPIF<br />FCFPPCIICCFPPFIICIFPPICICCFPFFFFCFPFICCFPFPFFCFPFI<br />CIFPCPCFPPFIICIIPIFFCFPFCIICICFCFPFFFCCFPFICCFPFPI<br />IPIFFCFPPCIICIIPIFFCFPFICIICIICIFPPICICCFPFFIFPICP<br />CFPFPFFCFPFICIFPCPIICIIPIFFCFPFCIICICPCFPFFFFCFPFI<br />CCFPFPCFPPCIICIFPPICICCFPFFFFCFPFICCFPFPCFPPCFCCFP<br />FICIICIIPIFFCFPFCIICICPCFPFFFFCFPFICCFPFPIIPIFFCFP<br />FICIICIIPIFFCFPPCIICIICIFPPICICCFPFFIFPCPCFPFPIFPI<br />CPFCCFPFICIICIIPIFFCFPFCIICICPCFPFFFCCFPFICCFPFPII<br />PIFFCFPPCIICCFPPFIICIFPPPCCFPFFFFCFPFICCFPFPFCCFPF<br />ICIFPCPCFPPFIICIIPIFFCFPFCIICICPCFPFFFCCFPFICCFPFP<br />IIPIFFCFPPCIICIIPIFFCFPFICIICIICIFPPPCCFPFFIFPICPC<br />FPFPFCCFPFICIFPCPIICIIPIFFCFPFCIICICICCFPFFFFCFPFI<br />CCFPFPCFPPCIICIFPPPCCFPFFFFCFPFICCFPFPCFPPCFFCFPFI<br />CIICIIPIFFCFPFCIICICICCFPFFFFCFPFICCFPFPIIPIFFCFPF<br />ICIICIIPIFFCFPPCIICIICIFPPPCCFPFFIFPCPCFPFPIFPICPF<br />FCFPFICIICIIPIFFCFPFCIICICICCFPFFFCCFPFICCFPFPCFPP<br />CIICIFPPICICCFPFFFFCFPFICCFPFPCFPPCFFCFPFICIICIIPI<br />FFCFPFCIICICICCFPFFFCCFPFICCFPFPIIPIFFCFPFICIICIIP<br />IFFCFPPCIICIICIFPPICICCFPFFIFPCPCFPFPIFPICPFFCFPFI<br />CIICIIPIFFCFPFCIICPCCFPFFFFCFPFICCFPFPIIPIFFCFPPCI<br />ICCFPPFIICIFPPICCCFPFFFFCFPFICCFPFPFFCFPFICIFPCPCF<br />PPFIICIIPIFFCFPFCIICPCCFPFFFFCFPFICCFPFPIIPIFFCFPP<br />CIICIIPIFFCFPFICIICIICIFPPICCCFPFFIFPICPCFPFPFFCFP<br />FICIFPCPIICIIPIFFCFPFCIICPCCFPFFFCCFPFICCFPFPIIPIF<br />FCFPPCIICCFPPFIICIFPPICPCFPFFFFCFPFICCFPFPFCCFPFIC<br />IFPCPCFPPFIICIIPIFFCFPFCIICPCCFPFFFCCFPFICCFPFPIIP<br />IFFCFPPCIICIIPIFFCFPFICIICIICIFPPICPCFPFFIFPICPCFP<br />FPFCCFPFICIFPCPIICIIPIFFCFPFCIICPFCFPFFFFCFPFICCFP<br />FPCFPPCIICIFPPICCCFPFFFFCFPFICCFPFPCFPPCFCCFPFICII<br />CIIPIFFCFPFCIICPFCFPFFFFCFPFICCFPFPIIPIFFCFPFICIIC<br />IIPIFFCFPPCIICIICIFPPICCCFPFFIFPCPCFPFPIFPICPFCCFP<br />FICIICIFFCFPFCPFCFPFFFCCFPFICIFFCFPPPIICIICIIPIFFC<br />FPPPIICIIPIFFCFPPFIICIIPIFFCFPPPIICIICIFPICPIFPCPI<br />FPICPIICICFFF</pre><br /><br />As a token, I leave you with this essence of my deepest result yet: 54c763a5f6b9beba26eeae2e98ba786f45b0fef8.<br /><br />EDIT: Thanks to Jochen for the correction. In case you were worrying, he is not a Fuun agent: I have carefully checked his patch.Quizhttp://www.blogger.com/profile/01935712406320139010noreply@blogger.com4