<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description></description><title>stuff &amp; things</title><generator>Tumblr (3.0; @learnr)</generator><link>http://blog.learnr.org/</link><item><title>Team composition</title><description>&lt;h4&gt;Team makeup&lt;/h4&gt;



&lt;p&gt;Pragmatist, Perfectionist, Crazy Smart&lt;/p&gt;



&lt;p&gt;&lt;a href="http://heroku.com/about"&gt;http://heroku.com/about&lt;/a&gt;&lt;/p&gt;



&lt;h4&gt;Interactions&lt;/h4&gt;

&lt;p&gt;&#13;&lt;/p&gt;

&lt;p&gt;A quote to start: This quote is the designers’ reflections on designing a programming language (SIMULA).&lt;/p&gt;



&lt;blockquote&gt;&#13;
&lt;p&gt;In the spring of 1967 a new employee at the NCC in a very shocked voice told the switchboard operator: “Two men are fighting violently in front of the blackboard in the upstairs corridor. What shall we do?” The operator came out of her office, listened for a few seconds and then said: “Relax, it’s only Dahl and Nygaard discussing SIMULA”.&lt;/p&gt;&#13;
&lt;p&gt;The story is true. The SIMULA 67 language was the outcome of ten months of an almost continuous sequence of battles and cooperation in front of that blackboard - interrupted by intervals when we worked in our neighbouring offices (communicating by shouting through the wall if necessary) or at home. (The people arranging this conference asked us to provide material relating to the development of our respective languages. We felt that the best thing we could have done was to bring along that blackboard. But we did not know for certain whether we would be flying a wide-body aircraft.)&lt;/p&gt;&#13;
&lt;p&gt;In some research teams a new idea is treated with loving care: “How interesting:”, “Beautiful:”. This was not the case in the SIMULA development. When one of us announced that he had a new idea, the other would brighten up and do his best to kill it off. Assuming that the person who got the idea is willing to fight, this is a far better mode of work than the mode of mutual admiration. We think it was useful for us, and we succeeded in discarding a very large number of proposals.&lt;/p&gt;&#13;
&lt;/blockquote&gt;



&lt;p&gt;(from &lt;a href="http://www.oberon2005.ru/paper/kn1978-01e.pdf"&gt;http://www.oberon2005.ru/paper/kn1978-01e.pdf&lt;/a&gt; via &lt;a href="http://lambda-the-ultimate.org/node/3107"&gt;http://lambda-the-ultimate.org/node/3107&lt;/a&gt;)&lt;/p&gt;



&lt;p&gt;Isn’t that &lt;b&gt;fantastic&lt;/b&gt;? You know that the “idea-defender” here would need to quickly detach himself from any silly latent emotional attachment to an idea. Any idea in that situation is going have to live on its own merits.&lt;/p&gt;



&lt;p&gt;If you’ve got someone who you know will rip into your shitty ideas with pointed criticism, then:&lt;/p&gt;



&lt;ol&gt;
&lt;li&gt;you’re not going to do dumb stuff; and&lt;/li&gt;&#13;
&lt;li&gt;you’re going to &lt;i&gt;know &lt;/i&gt;that you’ve got a winner when you get them on board.&lt;/li&gt;&#13;
&lt;/ol&gt;
&lt;p&gt;That kind of relationship is a huge asset. It’s one thing that turns you into (the very cliched) “more than the sum of your parts”. If you can do this, you’re really combining your 2+ brains effectively.&lt;/p&gt;



&lt;p&gt;Drop your ego, cultivate these relationships, and then hang on to them for dear life.&lt;/p&gt;</description><link>http://blog.learnr.org/post/61806567</link><guid>http://blog.learnr.org/post/61806567</guid><pubDate>Sun, 25 Oct 2009 18:23:10 -0700</pubDate></item><item><title>Really? REALLY? wtf.</title><description>&lt;pre&gt;&lt;p&gt;js&gt; x = [];&lt;br/&gt;&lt;br/&gt;js&gt; x[0] = "num0";&lt;br/&gt;num0&lt;br/&gt;js&gt; x[1] = "num1";&lt;br/&gt;num1&lt;br/&gt;js&gt; x[2] = "num2";&lt;br/&gt;num2&lt;br/&gt;js&gt; x&lt;br/&gt;num0,num1,num2&lt;br/&gt;js&gt; x["1"] = "str";&lt;br/&gt;str&lt;br/&gt;js&gt; x&lt;br/&gt;num0,str,num2&lt;br/&gt;js&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;p&gt;Someone please tell me there’s a way to avoid this idiotic behaviour.&lt;/p&gt;</description><link>http://blog.learnr.org/post/149021162</link><guid>http://blog.learnr.org/post/149021162</guid><pubDate>Sat, 25 Jul 2009 12:10:13 -0700</pubDate></item><item><title>ImgBurn rocks the shizzle.</title><description>&lt;img src="http://29.media.tumblr.com/jwsoJ3CssjrntviqnBvJPejto1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;ImgBurn rocks the shizzle.&lt;/p&gt;</description><link>http://blog.learnr.org/post/77087574</link><guid>http://blog.learnr.org/post/77087574</guid><pubDate>Mon, 09 Feb 2009 21:11:16 -0800</pubDate></item><item><title>Huzzah!</title><description>&lt;img src="http://25.media.tumblr.com/jwsoJ3Cssjaa1jztcv5Yzarpo1_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;p&gt;Huzzah!&lt;/p&gt;</description><link>http://blog.learnr.org/post/73907125</link><guid>http://blog.learnr.org/post/73907125</guid><pubDate>Wed, 28 Jan 2009 17:13:14 -0800</pubDate></item><item><title>First Clojure program</title><description>&lt;p&gt;So, I watched a few of Rich’s videos on &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt; a couple months back, but I finally got an afternoon to spend trying it out.&lt;/p&gt;
&lt;p&gt;I skimmed through &lt;a href="http://rubyquiz.com"&gt;Ruby Quiz&lt;/a&gt; to find an interesting but simple problem, and I decide to write a &lt;a href="http://www.rubyquiz.com/quiz5.html"&gt;Sokoban&lt;/a&gt; clone.&lt;/p&gt;
&lt;p&gt;My initial thought was to do it as a gui app, but I haven’t written any Java code since JDK 1.0-alpha in late 1995, and honestly, I didn’t really feel like putting effort into learning the Java GUI API only to end up with a bizarrely emulated, slightly broken GUI.&lt;/p&gt;
&lt;p&gt;So, I grabbed &lt;a href="http://github.com/weavejester/compojure/tree/master"&gt;Compojure&lt;/a&gt; off of git, and made the UI a hack webapp. (Yes, it’s bizarrely emulated and slightly broken still, but at least it was easy to write).&lt;/p&gt;
&lt;p&gt;First, have a look at the result: &lt;a href="http://h4ck3r.net:8000/"&gt;Clojban!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you care, the (probably horrible and un-idiomatic) code follows.&lt;/p&gt;
&lt;pre&gt;(ns clojban
  (:use (compojure html
                   http
                   file-utils)
        (clojure.contrib str-utils
                         seq-utils)
        (clojure set))
  (:import (java.util.regex Pattern)))

(defstruct pos :x :y)
(defstruct level
           :player ; pos
           :boxes  ; set-of-pos
           :goals  ; set-of-pos
           :walls  ; set-of-pos
           )

(defn explode
  "return a pos/type seq for each char in the line"
  [y line]
  (map (fn [x y type] (vector (struct pos x y) type))
       (iterate inc 0) (repeat y) line))

(defn line-explode
  "call explode on each line with the appropriate y"
  [lines]
  (let [linesplit (. Pattern compile "\n" (. Pattern MULTILINE))] ; must be a better way?
    (reduce into
            (map explode
                 (iterate inc 0)
                 (. linesplit split lines)))))

(defn filter-level
  "extracts a set of the pos's that match types"
  [expl-level type1 type2 &amp; type3]
  (set (map first
            (filter (fn [item]
                      (or (= (second item) type1)
                          (= (second item) type2)
                          (= (second item) type3)))
                    expl-level))))

(defn load-levels
  "load and return seq of level's"
  [filename]
  (let [contents (slurp filename)
        levelsplit (. Pattern compile "^$\n" (. Pattern MULTILINE)) ; each level separated by blank line
        levels (seq (. levelsplit split contents))]

    (map (fn [levelstr]
           (let [expl-level (line-explode levelstr)]
             (struct-map level
                         :player (first (filter-level expl-level \@ \+))
                         :boxes (filter-level expl-level \o \*)
                         :goals (filter-level expl-level \. \* \+)
                         :walls (filter-level expl-level \# \#))))
         levels)))

(def Levels (load-levels "sokoban_levels.txt"))
(def LvlWidth 19)
(def LvlHeight 16)
(def PlayerRenderOpen "♦")
(def PlayerRenderGoal "♦")
(def BoxRenderOpen "▨")
(def BoxRenderGoal "▨")
(def WallRender "█")
(def GoalRender "░")

(defn level-index [x y] (+ (* y LvlWidth) x))



(defn render-level-layer
  "my, what an insane level representation i have here"
  [target items if-empty if-full]
  (loop [target target
         remain (seq items)]
    (if remain
      (let [x (:x (first remain))
            y (:y (first remain))
            i (level-index x y)
            at (target i)]
        (recur (assoc target i (if (= at \space) if-empty if-full))
               (rest remain)))
      target)))

(defn render-level
  [lvl]
  (let [finallevel (reduce (fn [lvl data] (render-level-layer lvl (nth data 0) (nth data 1) (nth data 2))) ; todo how to splat `data'
                           (vec (replicate (* LvlWidth LvlHeight) \space))
                           `((~(:walls lvl) ~WallRender ~WallRender)
                             (~(:goals lvl) ~GoalRender ~GoalRender)
                             (~(:boxes lvl) ~BoxRenderOpen ~BoxRenderGoal)
                             (~(set (list (:player lvl))) ~PlayerRenderOpen ~PlayerRenderGoal)))]
    (dotimes y LvlHeight
      (print "")
      (dotimes x LvlWidth
        (print "")
        (print (finallevel (level-index x y)))
        (print ""))
      (print ""))))

(def AsciiToDx {72 -1,
                76  1,
                75  0,
                74  0})
(def AsciiToDy {72  0,
                74  1,
                75  -1,
                76  0})

(defn do-player-move
  "handle player movement, input is int ascii code for HJKL."
  [level input]
  (let [dx (get AsciiToDx input)
        dy (get AsciiToDy input)
        curpos (:player level)
        candidatepos (struct pos (+ (:x curpos) dx) (+ (:y curpos) dy))
        pastcandidatepos (struct pos (+ (:x curpos) dx dx) (+ (:y curpos) dy dy))
        walls (:walls level)
        boxes (:boxes level)]
    (if (walls candidatepos)
      level
      (if (boxes candidatepos)
        (if (or (walls pastcandidatepos) (boxes pastcandidatepos))
          level
          (assoc
            (assoc level :boxes (conj (disj boxes candidatepos) pastcandidatepos)) ; move box
            :player candidatepos)) ; and player
        (assoc level :player candidatepos))))) ; only player

(def JSCode "
function postwith (p) {
  var myForm = document.createElement('form');
  myForm.method='post';
  myForm.action='/';
  for (var k in p) {
    var myInput = document.createElement('input');
    myInput.setAttribute('name', k);
    myInput.setAttribute('value', p[k]);
    myForm.appendChild(myInput);
  }
  document.body.appendChild(myForm) ;
  myForm.submit() ;
  document.body.removeChild(myForm) ;
}

function handlekey(e) {
  if (!e) var e = window.event
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  if (code == 37) code = 72;
  if (code == 38) code = 75;
  if (code == 39) code = 76;
  if (code == 40) code = 74;
  if (code == 72 || code == 74 || code == 75 || code == 76 || code == 82 || code == 65 || code == 90) postwith({'code': code});
}
")

(defn restart-level [session]
  (alter session assoc :curlevel (or (session :curlevel) 0))
  (alter session assoc :complete (or (session :complete) (set nil)))
  (alter session assoc :nummoves 0)
  (alter session assoc :level (nth Levels (or (session :curlevel) 0))))

(defn next-level [session]
  (alter session assoc :curlevel (min
                                   (inc (session :curlevel))
                                   (- (count Levels) 1)))
  (restart-level session))

(defn prev-level [session]
  (alter session assoc :curlevel (max (dec (session :curlevel)) 0))
  (restart-level session))

(defservlet clojban-servlet
  (POST "/"
        (dosync
          (let [prevlevel (session :level)
                keycode (. Integer parseInt (params :code))]
            (if (= keycode 82)
              (restart-level session)
              (if (= keycode 65)
                (prev-level session)
                (if (= keycode 90)
                  (next-level session)
                  (let [moveresult (do-player-move prevlevel keycode)]
                    (if (= 0 (count (difference (:boxes moveresult) (:goals moveresult))))
                      (do
                        (alter session assoc :complete (conj (session :complete) (session :curlevel)))
                        (next-level session))
                      (do
                        (alter session assoc :nummoves (inc (session :nummoves)))
                        (alter session assoc :level moveresult)))))))))
        (redirect-to "/"))
  (GET "/"
       (let [levelstate (or (session :level) (dosync (restart-level session) (session :level)))]
         [{"Content-Type" "text/html"}
          (html
            (doctype :xhtml-transitional)
            [:html {:xmlns "http://www.w3.org/1999/xhtml" :lang "en"}
             [:head
              [:title "Clojban!"]
              [:meta {:http-equiv "Content-Type", :content "text/html; charset=utf-8"}]
              [:script {:type "text/javascript"} JSCode]]
             [:body {:onkeydown "handlekey(event);" :style "font-family: arial; font-size: 13px;"}
              [:h1 {:style "font-family: arial;"} "Clojban"]
              [:p "This is a silly &lt;i&gt;Sokoban&lt;/i&gt; implemented in " (link-to "http://clojure.org" "Clojure") ". It's hitting the server every time you move (rather than Javascript) so it might not respond too quickly. The unicode box drawing craziness looks OK in FF, and reasonable in IE, but not so hot in Chrome/Webkit. Sorry."]
              [:table {:style "border-style: none; font-size: 36px; font-family: courier; padding: 0px 0px 0px 0px; margin:0px 0px 0px 0px; line-height: 1em;"
                       :border "0"
                       :cellpadding "0"
                       :cellspacing "0"}
               (with-out-str (render-level levelstate))]
              [:p "Use arrow keys or hjkl to move all the boxes into the goals. Press r to restart level, or a/z to give up and skip through levels."]
              [:p "Level: " (session :curlevel)]
              [:p "Moves: " (session :nummoves)]
              [:p "Completed: " (str-join " " (map (fn [i]
                                                     (let [complete (session :complete)]
                                                       (format "%d"
                                                               (if (complete i) "green" "#ccc")
                                                               i)))
                                                   (range (count Levels))))]
              ]])]))
  (ANY "*"
       (page-not-found)))
&lt;/pre&gt;</description><link>http://blog.learnr.org/post/59883018</link><guid>http://blog.learnr.org/post/59883018</guid><pubDate>Sat, 15 Nov 2008 16:47:00 -0800</pubDate></item><item><title>Configuring Vim, some more</title><description>&lt;p&gt;As an addendum to &lt;a href="http://items.sjbach.com/319/configuring-vim-right"&gt;http://items.sjbach.com/319/configuring-vim-right&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here’s a few more that I think are un-live-able-without:&lt;/p&gt;
&lt;pre&gt;&lt;p&gt;" ease of use keyboard mappings (why do I care about top/bottom of screen?)&lt;br/&gt;map H ^&lt;br/&gt;map L $&lt;br/&gt;&lt;br/&gt;" buffer switching/management, might as well use those keys for something useful&lt;br/&gt;map &lt;Right&gt; :bnext&lt;CR&gt;&lt;br/&gt;imap &lt;Right&gt; &lt;ESC&gt;:bnext&lt;CR&gt;&lt;br/&gt;map &lt;Left&gt; :bprev&lt;CR&gt;&lt;br/&gt;imap &lt;Left&gt; &lt;ESC&gt;:bprev&lt;CR&gt;&lt;br/&gt;map &lt;Del&gt; :bd&lt;CR&gt;&lt;br/&gt;&lt;br/&gt;" get rid of stupid scrollbar/menu/tabs/etc&lt;br/&gt;set guioptions=a&lt;br/&gt;&lt;br/&gt;" don't need /g after :s or :g&lt;br/&gt;set gdefault&lt;br/&gt;&lt;br/&gt;" i prefer this to visualbell&lt;br/&gt;set noerrorbells&lt;br/&gt;

" Hide the mouse pointer while typing&lt;br/&gt;set mousehide&lt;/p&gt;&lt;/pre&gt;
&lt;p&gt;I’ve used all of these for longer than I can remember, probably time to troll through recent help files and vim.org to find new and exciting juicy settings.&lt;/p&gt;
&lt;p&gt;EDIT: forgot the one I miss the most when I don’t have my .vimrc:&lt;/p&gt;
&lt;p&gt;cab o find&lt;/p&gt;
&lt;p&gt;so that :o does something useful. I’d like one of the emacs-style smart-fuzz-file-opener command line thing, I should probably hunt around for a plugin to do that.&lt;/p&gt;</description><link>http://blog.learnr.org/post/59098925</link><guid>http://blog.learnr.org/post/59098925</guid><pubDate>Mon, 10 Nov 2008 23:14:00 -0800</pubDate></item><item><title>Bill C-61</title><description>&lt;p&gt;Canada’s Bill C-61 is an even-worse version of the United States’ DMCA.&lt;/p&gt;
&lt;p&gt;For more information, &lt;a href="http://www.michaelgeist.ca/"&gt;http://www.michaelgeist.ca/&lt;/a&gt; is a reasonable starting point. I rolled up my sleeves and had a go at &lt;a href="http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473&amp;file=4"&gt;http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473&amp;file=4&lt;/a&gt; which is relatively readable.&lt;/p&gt;
&lt;p&gt;Here’s the letter I just posted (yes, on actual paper, in an envelope!) to my MP.&lt;/p&gt;
&lt;p&gt;If you’re Canadian, please read the above links and if you don’t agree with this Bill, as I’m confident you won’t, phone or write to your MP (especially if your MP is a Conservative Party member!)&lt;/p&gt;
&lt;p&gt;————————————&lt;/p&gt;
&lt;p&gt;Office of the Honourable Dr. Hedy Fry, P.C., M.P.&lt;br id="igah"/&gt; Confederation Building House of Commons&lt;br id="igah0"/&gt; Ottawa, Ontario&lt;br id="igah1"/&gt; K1A 0A6&lt;br id="vau3"/&gt;&lt;br id="igah2"/&gt; Hello Dr. Fry&lt;br id="igah3"/&gt;&lt;br id="igah4"/&gt; I am a resident of Vancouver Centre, and I’m writing to you to express my absolute horror at the current state of Bill C-61.&lt;br id="lnha"/&gt;&lt;br id="om_s"/&gt; I am employed as a software engineer in the entertainment industry, and as such, fully respect and understand the need for copyright reform in Canada.&lt;br id="om_s0"/&gt;&lt;br id="lnha0"/&gt; However, from reading this bill (at &lt;a href="http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473"&gt;http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473&lt;/a&gt;), the reproduction rights afforded to Canadians are absolutely useless because of section 29.21(c). This section subordinates any time-shifting and media-shifting rights that should be allowed, merely by having any kind of digital lock mechanism on the content. But, virtually all media sold in Canada now contains a digital lock of some sort, so it’s almost pointless to “grant” these rights.&lt;br id="g_.g"/&gt;&lt;br id="g_.g0"/&gt; Inevitably, the devices or internet services which control the digital lock access fail, go out of business, or otherwise are not maintained. If we are unable to legally shift to other formats, and the media become un-unlockable, they are effectively gone. Will all of the companies and individuals controlling the locks exist in 5 years? Maybe. 50 years? Unlikely.&lt;br id="d53y"/&gt;&lt;br id="d53y0"/&gt; I would also like to especially point out that this does not solely concern things that could perhaps be considered “frivolous”, like pop-consumer-ish music and video. Over the next 10-15 years, it is all but guaranteed that most books, and crucially text books, will be delivered and consumed in electronic form. My wife is a high school teacher employed by the Vancouver School Board, and I would be horrified to find that our already underfunded education system had lost access to teaching resources, simply because the company controlling a digital lock had failed.&lt;br id="fyjy"/&gt;&lt;br id="fyjy0"/&gt; I sincerely hope you will make sure that this Bill is heavily modified, or defeated, when the time comes.&lt;br id="fyjy1"/&gt;&lt;br id="fyjy2"/&gt; Thank you for your time,&lt;br id="kyw2"/&gt;&lt;br id="i9x6"/&gt;&lt;br id="i9x60"/&gt;&lt;br id="i9x61"/&gt;&lt;br id="i9x62"/&gt;&lt;br id="fyjy3"/&gt; Scott Graham&lt;br id="fyjy4"/&gt; &lt;my address removed&gt;&lt;/p&gt;</description><link>http://blog.learnr.org/post/47257225</link><guid>http://blog.learnr.org/post/47257225</guid><pubDate>Sun, 24 Aug 2008 18:48:54 -0700</pubDate></item><item><title>Braid</title><description>&lt;p&gt;Braid is very cool. I often enjoyed reading &lt;i&gt;The Inner Product&lt;/i&gt; in GDMag, but always got the impression Jonathan was a little “ivory tower”. Turns out, I don’t know shit. Congrats to Mr Blow! (just grabbed the full 360 version: it’s fantastic).&lt;/p&gt;</description><link>http://blog.learnr.org/post/45388957</link><guid>http://blog.learnr.org/post/45388957</guid><pubDate>Sat, 09 Aug 2008 23:49:49 -0700</pubDate></item><item><title>floating point</title><description>&lt;p&gt;Floating-point tends to chafe my ass. I was thinking perhaps I’d try to really understand it. These look interesting:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://citeseer.ist.psu.edu/goldberg91what.html"&gt;http://citeseer.ist.psu.edu/goldberg91what.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.cant.ua.ac.be/ieeecc754.html"&gt;http://www.cant.ua.ac.be/ieeecc754.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://fluorescence.fjfi.cvut.cz/~adamek/nm/ieee754.pdf"&gt;http://fluorescence.fjfi.cvut.cz/~adamek/nm/ieee754.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Only way to understand something is to implement it though…&lt;/p&gt;
&lt;p&gt;&lt;b&gt;[Update]&lt;/b&gt;: even better by the looks of it: &lt;a href="http://docs.sun.com/source/806-3568/ncgTOC.html"&gt;http://docs.sun.com/source/806-3568/ncgTOC.html&lt;/a&gt;&lt;/p&gt;</description><link>http://blog.learnr.org/post/45024754</link><guid>http://blog.learnr.org/post/45024754</guid><pubDate>Wed, 06 Aug 2008 21:42:00 -0700</pubDate></item><item><title>Second "das keyboard"</title><description>&lt;p&gt;So, I just got my second &lt;a href="http://www.daskeyboard.com/"&gt;http://www.daskeyboard.com/&lt;/a&gt; in the mail. The first one I had was the “original”, and I loved and continue to love it. I’ve been using it as my work keyboard (where I do the majority of my coding) for the last 3 years or so.&lt;/p&gt;
&lt;p&gt;I just got a second one, but it’s the “new” version (the only one they offer now). It’s cleaner design-wise, but there’s some things that I think they’ve made worse.&lt;/p&gt;
&lt;p&gt;The first is that the keyboard is just too thick. It’s gotten half an inch (or so) thicker. It feels more solid now, and is quite a bit heavier (so it doesn’t move around at all, which is nice), but the angle of my forearms is slightly higher, which inevitably means my wrists are more crooked when I get more tired and drop my arms, and slouch, etc. Don’t like that very much, especially as I’ve had some wrist and arm pain recently.&lt;/p&gt;
&lt;p&gt;They also seem to have killed the variable resistance on keys (or at least tuned them differently). The only key I notice that’s harder resistance is the backspace key, whereas the space key used to have a lot more resistance, and doesn’t all now. Perhaps the resistance has changed over time on my original one, so it’s just a matter of getting used to this one, or breaking it in more. Maybe it’s more expensive to do the bands of keys with different resistances, but I’m pretty sad about it, especially since this one ended up being about 30% more expensive than the original.&lt;/p&gt;
&lt;p&gt;Oh, and the F and J have icky bumps instead of being nicely scooped. :( I’m guessing that one was a concession to people who weren’t very good typists, and couldn’t find the home row, but I prefer the scoops, since we are going for “stealth” here, after all. They just felt nicer on your finger tips too.&lt;/p&gt;
&lt;p&gt;The sound of the switches has changed too, but that’s just… different, not really better or worse.&lt;/p&gt;
&lt;p&gt;I’m going to guard my old one even more carefully now with the knowledge that they’re not &lt;i&gt;really &lt;/i&gt;replaceable. Hopefully I’ll grow to love the new one as much, but the jury’s still out.&lt;/p&gt;</description><link>http://blog.learnr.org/post/44016829</link><guid>http://blog.learnr.org/post/44016829</guid><pubDate>Tue, 29 Jul 2008 19:25:38 -0700</pubDate></item><item><title>Problems with Vinagre</title><description>&lt;p&gt;So, the default remote desktop app in Ubuntu changed from, um, I don’t know what actually, to a new app called “Vinagre”.&lt;/p&gt;
&lt;p&gt;You’d think that’d be something I wouldn’t give a patooty about. The first thing you notice is that it has a list on the side that lets you keep track of servers you connect to which seemed nice enough.&lt;/p&gt;
&lt;p&gt;I didn’t use it much at first, so I thought nothing more about it.&lt;/p&gt;
&lt;p&gt;Today, I started using it. Dear god:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Tried to connect to a fully up-to-date Fedora box (from a fully up-to-date Ubuntu). vino-server crashes on the Fedora machine. I don’t know who’s fault it is, but I don’t really care. Working around that by using XDMCP for the time being, but that’s pretty irritating, interface-wise.&lt;/li&gt;
&lt;li&gt;While repeatedly trying to connect to the Fedora box (it silently fails on the Ubuntu machine), Vinagre doesn’t save the last-entered machine name, so I have to keep entering “192.168.0….” every time. Irritating.&lt;/li&gt;
&lt;li&gt;Insanely hard to send Ctrl-Alt-Del to log into Windows machines. For same reason, Ctrl-Alt was chosen as the “Capture/Release” input. So, in order to send Ctrl-Alt-Del to login to a Windows box, you have to first focus the Viagre app (click/whatever), then make sure you’ve &lt;i&gt;&lt;b&gt;uncaptured&lt;/b&gt;&lt;/i&gt; the input by doing Ctrl-Alt, then finally, &lt;b&gt;&lt;i&gt;recapture&lt;/i&gt;&lt;/b&gt; the input by doing Ctrl-Alt again, and &lt;i&gt;&lt;b&gt;then without letting go&lt;/b&gt;&lt;/i&gt; of Ctrl-Alt, press Del to get the final combo. If you just push that combo of course, the Ctrl-Alt first removes capture, and then sends Ctrl-Alt-Del to the local machine. Not very intuitive, especially since there’s very little (no?) indication of whether input is captured.&lt;/li&gt;
&lt;li&gt;Related, there seems to be absolutely no way to send F11 to the client machine. The general hotkey behaviour is irritating enough as it is: Alt-F4 closes either all of Vinagre, or an app on the client, depending on whether you’ve pressed Ctrl-Alt recently, with no indication of which “mode” you’re in). But, it seems that F11 is even worse. If you’re in captured mode, then most things seem to be sent to the target machien, but apparently F11 was deemed too important to be handled normally, and there’s no configuration mechanism. Fine, until I try to debug something and naturally hit F11 to “Step Into” a function.&lt;/li&gt;
&lt;li&gt;
&lt;b&gt;[Update]&lt;/b&gt; When input is captured, there’s no way to scroll the virtual desktop if it’s bigger than your current monitor. WTF?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Basically, it just seems like this app was pushed out way too quick to the main/default user stream. Please give me back my old VNC/RDP viewer. :(&lt;/p&gt;</description><link>http://blog.learnr.org/post/43640887</link><guid>http://blog.learnr.org/post/43640887</guid><pubDate>Sat, 26 Jul 2008 13:20:00 -0700</pubDate></item><item><title>Windows iTunes</title><description>&lt;p&gt;I genuinely don’t understand.&lt;/p&gt;
&lt;p&gt;I’m not trying to be difficult. I really tried to use iTunes this time. It seemed like the march of inevitability if I wanted to get iPhone apps, and I thought perhaps it would be nice to use. I grabbed the new 7.7 that has iPhone apps, since I wanted to have a look at what was available. It was a little large at 60meg, but hey, whatever, there’s lots of bandwidth to go around these days.&lt;/p&gt;
&lt;p&gt;First of all, I had to &lt;b&gt;reboot &lt;/b&gt;after installing it. Insane. Strike one. If that was it, well fine. But it’s &lt;b&gt;&lt;i&gt;completely &lt;/i&gt;&lt;/b&gt;unusably slow on my laptop. The laptop is about 2 years old. It was Dell’s top-of-the-line (XPS M170) when I bought it, so it’s not crazy fast, but it’s not so slow either. I’m pretty sure that it’s still well above the current median machine in performance.&lt;/p&gt;
&lt;p&gt;I added my music collection (largely stored on a network drive). It’s about 65 gig, comprised mostly of mp3s and flacs, both ripped from CDs and downloaded. Maybe a little larger than some collections, but certainly not unreasonably large.&lt;/p&gt;
&lt;p&gt;I started the “Import” last night around 8pm. It’s now 2pm the next day, and it’s still trying to download album artwork. That’d be fine, except that apparently while it’s doing that, it’s impossible for the UI to be responsive. WTF! Is this goddamn amateur hour? It only refreshes the UI at the end of each attempt to download an album cover?!&lt;/p&gt;
&lt;p&gt;Pausing or unpausing music, or changing the volume (since apparently it feels the need to steal the functionality hardware media keys) takes over 10 seconds. That is not hyperbole! It actually takes longer than 10 seconds for anything to happen. On top of that, the mouse event handling also appears to be “sampling” rather than using the event queue properly, because if I just click the play/pause button nothing happens. I have to &lt;b&gt;&lt;i&gt;hold the fucking mouse button down&lt;/i&gt;&lt;/b&gt; until the UI responds (10 to 15 seconds, remember!), putting the button into the down state, and then release it.&lt;/p&gt;
&lt;p&gt;On a side note, iTunes.exe currently owns roughly 300 threads, and has had a continuous IO delta of around 500k/sec for nearly 24 hours now. Jumped up Jesus Christ. You’re not controlling air traffic, you’re cataloging and playing some fucking music.&lt;/p&gt;
&lt;p&gt;If this is Apple’s shitty attempt to create some sort of Mac “halo”, they’ve failed miserably. With 100% certainty, I will never, ever, by a Mac with this as the demo of the user experience.&lt;/p&gt;</description><link>http://blog.learnr.org/post/42030137</link><guid>http://blog.learnr.org/post/42030137</guid><pubDate>Sat, 12 Jul 2008 13:46:56 -0700</pubDate></item><item><title>Project Euler, problem #10 in F#</title><description>&lt;p&gt;Problem’s quite simply stated this time:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.&lt;/p&gt;
&lt;p&gt;Find the sum of all the primes below two million.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First typed in solution was simply:&lt;/p&gt;
&lt;pre&gt;[2..1999999]&lt;br/&gt;|&gt; Seq.filter(isprime)&lt;br/&gt;|&gt; Seq.fold1(+)&lt;/pre&gt;
&lt;p&gt;Which got me a number pretty quickly that looked lovely, but was completely wrong. I ran it again, apparently hoping that’d it magically be right the second time. Then I tried for those below 1000000 instead and the sum was negative. Oops! So, the quick fix and working version (changing the “int” range to “bigint” range):&lt;/p&gt;
&lt;pre&gt;[2I..1999999I]&lt;br/&gt;|&gt; Seq.filter(fun x -&gt; isprime(int x))&lt;br/&gt;|&gt; Seq.fold1(+)&lt;/pre&gt;
&lt;p&gt;I wonder if there’s a checked-overflow-arithmetic version of F#? Might be useful for some of these questions, since they’re so computationally light anyway.&lt;/p&gt;</description><link>http://blog.learnr.org/post/35358856</link><guid>http://blog.learnr.org/post/35358856</guid><pubDate>Sat, 12 Jul 2008 13:23:31 -0700</pubDate></item><item><title>FSharp Euler #9</title><description>&lt;p&gt;The problem statement:&lt;/p&gt; &lt;blockquote&gt;
&lt;p&gt;A Pythagorean triplet is a set of three natural numbers, a  &lt;/p&gt; a&lt;sup&gt;2&lt;/sup&gt; + b&lt;sup&gt;2&lt;/sup&gt; = c&lt;sup&gt;2&lt;/sup&gt;&lt;p&gt;For example, 3&lt;sup&gt;2&lt;/sup&gt; + 4&lt;sup&gt;2&lt;/sup&gt; = 9 + 16 = 25 = 5&lt;sup&gt;2&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There exists exactly one Pythagorean triplet for which a + b + c = 1000.&lt;/p&gt;
&lt;p&gt;Find the product abc.&lt;/p&gt;
&lt;/blockquote&gt;    &lt;p&gt;This is another one that’s probably really more “math”-y than programming-y, but I’m enjoying using my new F# hammer to solve these, so might as well keep at it.&lt;/p&gt;
&lt;p&gt;It seems like another nice make-a-sequence-and-then-filter-it, but just doing 1..1000 for a, b, and c, results in an awfully big sequence (a billion long). So, a couple simple observations to make the numbers a lot smaller. The main one is that you can just make c = 1000 - a - b, since we know that all answers have to have that form anyway, and then we know a &lt;/p&gt;
&lt;pre&gt;seq { for a in 1..1000 do&lt;br/&gt;        for b in a..1000 do&lt;br/&gt;            let c = 1000 - a - b&lt;br/&gt;            yield (a,b,c) }&lt;br/&gt;|&gt; Seq.first(fun (a,b,c) -&gt; if a*a + b*b = c*c then Some(a,b,c) else None)&lt;/pre&gt;
&lt;p&gt;Voila! &lt;/p&gt;</description><link>http://blog.learnr.org/post/35357039</link><guid>http://blog.learnr.org/post/35357039</guid><pubDate>Sat, 24 May 2008 10:56:01 -0700</pubDate></item><item><title>Euler #8 in FSharp</title><description>&lt;p&gt;The problem:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Find the greatest product of five consecutive digits in the 1000-digit number.&lt;/p&gt; 73167176531330624919225119674426574742355349194934&lt;br/&gt; 96983520312774506326239578318016984801869478851843&lt;br/&gt; 85861560789112949495459501737958331952853208805511&lt;br/&gt; 12540698747158523863050715693290963295227443043557&lt;br/&gt; 66896648950445244523161731856403098711121722383113&lt;br/&gt; 62229893423380308135336276614282806444486645238749&lt;br/&gt; 30358907296290491560440772390713810515859307960866&lt;br/&gt; 70172427121883998797908792274921901699720888093776&lt;br/&gt; 65727333001053367881220235421809751254540594752243&lt;br/&gt; 52584907711670556013604839586446706324415722155397&lt;br/&gt; 53697817977846174064955149290862569321978468622482&lt;br/&gt; 83972241375657056057490261407972968652414535100474&lt;br/&gt; 82166370484403199890008895243450658541227588666881&lt;br/&gt; 16427171479924442928230863465674813919123162824586&lt;br/&gt; 17866458359124566529476545682848912883142607690042&lt;br/&gt; 24219022671055626321111109370544217506941658960408&lt;br/&gt; 07198403850962455444362981230987879927244284909188&lt;br/&gt; 84580156166097919133875499200524063689912560717606&lt;br/&gt; 05886116467109405077541002256983155200055935729725&lt;br/&gt; 71636269561882670428252483600823257530420752963450&lt;/blockquote&gt;
&lt;p&gt; Treating it as a number is probably not going to be too pleasant.&lt;/p&gt;
&lt;pre&gt;let prob8num = "7316 ... 52963450"&lt;br/&gt;let chars = prob8num.ToCharArray() |&gt; Array.map(fun x -&gt; Char.code(x) - Char.code('0'))&lt;br/&gt;let rec prob8 (rest : array) =&lt;br/&gt;    if rest.Length     else&lt;br/&gt;        let tl = Array.sub rest 1 (rest.Length - 1)&lt;br/&gt;        let curProd = Array.sub rest 0 5 |&gt; Array.reduce_left( * )&lt;br/&gt;        Math.Max(prob8(tl), curProd)&lt;br/&gt;prob8 chars&lt;br/&gt;&lt;/pre&gt;
&lt;p&gt; So, store it as a string, but then convert it to a character array, and map to the actual numerical values (assuming ASCII I guess).&lt;/p&gt;
&lt;p&gt;From that, just a simple recursive solution that does way too much Array.sub’ing. It would make much more sense to use List’s instead of Array’s for all of those .subs, but, there was no sub extraction built into List so I just did it that way instead. &lt;/p&gt;
&lt;p&gt;I wrestled a little with the syntax of F# again in this question. I tried putting the “let tl” as inline into the body of the call to Math.Max, but I couldn’t get it to work correctly. Not sure what the required syntax is, maybe I need some of the keywords that I don’t know from non-#light yet?&lt;/p&gt;
&lt;p&gt;Also, my copy of Expert F# has arrived, so I’m just starting to peruse it now. Hopefully my code will become more idiomatic soon enough. &lt;/p&gt;
&lt;p&gt;And man, do I hate blog software’s handling of code. You’d think that maybe if I typed a less-than sign they could figure out how to escape it moderately properly, but apparently that’s way to complicated. Idiotic. &lt;/p&gt;</description><link>http://blog.learnr.org/post/34790729</link><guid>http://blog.learnr.org/post/34790729</guid><pubDate>Mon, 19 May 2008 13:59:00 -0700</pubDate></item><item><title>Project Euler, problem #7 in FSharp</title><description>The problem is:  &lt;blockquote&gt;
&lt;p&gt;By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6&lt;sup&gt;th&lt;/sup&gt; prime is 13.&lt;/p&gt;
&lt;p&gt;What is the 10001&lt;sup&gt;st &lt;/sup&gt;prime number?&lt;/p&gt;
&lt;/blockquote&gt;   Well, this sort of looks like another one that’s intended more for pencil-and-paper solvers than programming-language solvers. But, maybe prime #10001 is very big, so it becomes a problem for code too. My first thought is just to loop with a counter until we find the 10001st number, but that involves variables which I’m apparently trying to avoid in these problems. I didn’t get to use infinite lists in the last question, so let’s try again:&lt;pre&gt;let rec getprime(n) =&lt;br/&gt;    if n = 1 then 2&lt;br/&gt;    else&lt;br/&gt;        let prev = getprime(n - 1)&lt;br/&gt;        Seq.init_infinite(fun x -&gt; x + prev + 1)&lt;br/&gt;        |&gt; Seq.find(isprime)getprime(10001)&lt;/pre&gt;
&lt;p&gt;First, we assume we have the previous prime (say it’s “11”). Then, we generate an infinite list starting at the next number (i.e. [12..inf]). Then, find the first number in that list that’s prime, which is the prime after the previous one, which is the one we’re looking for. Finally, take that functionality and wrap it in a recursion stopping at prime #1 = 2 and we’re done.&lt;/p&gt;
&lt;p&gt;When I first typed this code in, I messed up the initial value for the start of the sequence as (x + prev), which of course meant it kept finding “2” as the answer. Just a dumb mistake, but the interesting part is that I’d forgotten I even had a debugger since I was getting so used to using FSI to run bits of code. In the end I found the mistake by replacing Seq.find with Seq.nth(0), and adding a couple Console.WriteLine()s.&lt;/p&gt;
&lt;p&gt;It’d be really nice if there was a way to put focus onto the FSI tab window though. I find myself defining functions by using Alt-Enter on the body of the function in the text editor, and then wanting to switch to the window to try passing it a few values to see how it works. Without a shortcut, I have to grab the mouse, click in the right place, sometimes Ctrl-End to find the prompt, etc. Maybe I just haven’t found the key yet, not sure. &lt;/p&gt;</description><link>http://blog.learnr.org/post/34630452</link><guid>http://blog.learnr.org/post/34630452</guid><pubDate>Sun, 18 May 2008 17:04:11 -0700</pubDate></item><item><title>Euler Project in F#, problem #6</title><description>&lt;p&gt;Kick it, Euler: &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sum of the squares of the first ten natural numbers is,&lt;/p&gt;1² + 2² + … + 10² = 385&lt;p&gt;The square of the sum of the first ten natural numbers is,&lt;/p&gt;(1 + 2 + … + 10)² = 55² = 3025&lt;p&gt;Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640.&lt;/p&gt;
&lt;p&gt;Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not much to this one. I learned about the exponentiation operator which seems to be a rewrite to calling a Pow method (it doesn’t seem to work on int). Here’s a “my brain is currently warped into thinking about everything as a sequence and operations on sequences”-solution:&lt;/p&gt;
&lt;pre&gt;([1.0..100.0] |&gt; Seq.fold (+) 0.0) ** 2.0&lt;br/&gt;- ([1.0..100.0] |&gt; Seq.map(fun x -&gt; x*x) |&gt; Seq.fold(+) 0.0)&lt;/pre&gt;
&lt;p&gt;See y’all next time. &lt;/p&gt;</description><link>http://blog.learnr.org/post/34616882</link><guid>http://blog.learnr.org/post/34616882</guid><pubDate>Thu, 15 May 2008 11:08:48 -0700</pubDate></item><item><title>Euler is streaking in F#, problem #5</title><description>&lt;p&gt;Problem #5: &lt;/p&gt; &lt;blockquote&gt;
&lt;p&gt;2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.&lt;/p&gt;
&lt;p&gt;What is the smallest number that is evenly divisible by all of the numbers from 1 to 20?&lt;/p&gt;
&lt;/blockquote&gt;   &lt;p&gt;&lt;a href="http://blog.learnr.org/post/34614520"&gt;Speaking of infinite sequences&lt;/a&gt;, here’s the solution that seemed obvious to me at first.&lt;/p&gt;
&lt;pre&gt;open Microsoft.FSharp.Math&lt;br/&gt;Seq.init_infinite (fun x -&gt; BigInt.FromInt32 x)&lt;br/&gt;|&gt; Seq.find(fun (x:BigInt) -&gt;&lt;br/&gt;    x &gt; 1I &amp;&amp; Seq.for_all (fun (n:BigInt) -&gt; x % n = 0I) [1I..20I])&lt;/pre&gt;
&lt;p&gt;Nice and simple, just iterate through all numbers, and find the first ne that’s evenly divisible by all the numbers from 1 to 20. Unfortunately let it run for an hour (!) while I had dinner, and it hadn’t completed. I just assumed was doing something dumb, but it seems to give sensible answers for the numbers in the range of 1..10 and 1..16. Apparently, at 1..17 or more though the answer becomes “quite” large. The first version just used int32’s rather than BigInt; I thought perhaps it was getting past 2^32 and so never finding the answer, but it’s hard to say since I wasn’t prepared to wait any longer for the BigInt version to finish.&lt;br/&gt;&lt;br/&gt;As a side note, the bigint stuff is a bit ugly in this example, I guess an unfortunate side effect of .NET showing through where the numerical stack is fractured (sensibly and everything, just a little unfortunate here).&lt;br/&gt;&lt;br/&gt;In any case, a more mathematical and less brute-force algorithmic approach seems to be required for this problem.&lt;br/&gt;&lt;br/&gt;Here’s one that takes only milliseconds to run based on:&lt;br/&gt;&lt;a href="http://en.wikipedia.org/wiki/Least_common_multiple#Alternative_method"&gt;http://en.wikipedia.org/wiki/Least_common_multiple#Alternative_method&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;let rec numTimes(x, p) =&lt;br/&gt;    if x % p = 0 then numTimes(x / p, p) + 1&lt;br/&gt;    else 0&lt;br/&gt;let maxNumTimes p =&lt;br/&gt;    let num = float([1..20] |&gt; Seq.map(fun x -&gt; numTimes(x, p)) |&gt; Seq.fold(max) 0)&lt;br/&gt;    int(Math.Pow(float(p), num))&lt;br/&gt;[1..20]&lt;br/&gt;|&gt; Seq.filter(isprime)&lt;br/&gt;|&gt; Seq.map(maxNumTimes)&lt;br/&gt;|&gt; Seq.fold1( * )&lt;/pre&gt;
&lt;p&gt;For all primes in the range, figure out the maximum number of times that prime appears in the prime factorization of any of the numbers, and find the product of those primes raised to the maximum number of powers. I learned a little F# in this one, but as far as the math, it would have taken me a long while to recall or figure that out, so it was basically just implementing what Wikipedia described. Oh well.&lt;/p&gt;
&lt;p&gt;My “fold” got one better again, instead of passing a pointless anon function and a pointless initial value, last time I got rid of the function. This time I found “fold1” and got rid of the non-useful initial value too! :) &lt;/p&gt;</description><link>http://blog.learnr.org/post/34616056</link><guid>http://blog.learnr.org/post/34616056</guid><pubDate>Tue, 13 May 2008 21:44:39 -0700</pubDate></item><item><title>"…

Because we couldn’t see how the system worked anymore!

Small systems are not only..."</title><description>“&lt;p&gt;…&lt;/p&gt;

&lt;p&gt;Because we couldn’t see how the system worked anymore!&lt;/p&gt;

&lt;p&gt;Small systems are not only easier to optimize, they’re possible to optimize. And I mean globally optimize.&lt;/p&gt;

&lt;p&gt;So when we talk about performance, it’s all crap. The most important thing is that you have a small system. And then the performance will just fall out of it naturally.&lt;/p&gt;”&lt;br/&gt;&lt;br/&gt; - &lt;em&gt;&lt;a href="http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html"&gt;http://steve-yegge.blogspot.com/2008/05/dynamic-languages-strike-back.html&lt;/a&gt;&lt;/em&gt;</description><link>http://blog.learnr.org/post/34630685</link><guid>http://blog.learnr.org/post/34630685</guid><pubDate>Tue, 13 May 2008 00:56:48 -0700</pubDate></item><item><title>Some more Euler Project, problem #4</title><description>&lt;p&gt;This one was pretty straightforward.&lt;/p&gt;  &lt;blockquote&gt;
&lt;p&gt;A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.&lt;/p&gt;
&lt;p&gt;Find the largest palindrome made from the product of two 3-digit numbers.&lt;/p&gt;
&lt;/blockquote&gt;   &lt;p&gt;The hardest part was just reversing the number to be able to tell if it was a palindrome. Unfortunately, when I searched for “reverse string f#” I got &lt;a href="http://basildoncoder.com/blog/2008/04/21/project-euler-problem-4/"&gt;http://basildoncoder.com/blog/2008/04/21/project-euler-problem-4/&lt;/a&gt; which while certainly a good search result, could have ruined the fun. Anyhow: the solution to reverse (why the heck isn’t there a .Reverse on the .net string anyway?) is the obvious thing. The only thing notable thing here is the “:string” on the argument to the function which is the first time I’ve had to write a type other than the type coercions from float &lt;-&gt; int. It reminds me of the irritating problem with C# generics where it’s often not possible to write the generic function because it has to be completely generic, or has to implement an interface so the type can be where-constrained (or in other words, generics are generics, not templates,  I guess. The C++ approach definitely has benefits, sometimes, though.)&lt;/p&gt;
&lt;pre&gt;let rev (s:string) = new string(Array.rev(s.ToCharArray()))&lt;br/&gt;&lt;br/&gt;{ for i in [100..999] do&lt;br/&gt;    for j in [100..999] do&lt;br/&gt;        let x = i * j&lt;br/&gt;        if x.ToString() = rev(x.ToString()) then yield x }&lt;br/&gt;|&gt; Seq.fold(max) 0&lt;/pre&gt;
&lt;p&gt;After that, it’s pretty simple. I just make a list of all the palindromes created from 3 digit multiplicands, and then fold out the maximum of those. I noticed something very dumb in the last solution, I was folding an anonymous function that just directly passed its arguments to max, which is of course silly. I’m finding F#’s syntax a little weird, but getting better.&lt;/p&gt;
&lt;p&gt;It occurs to me after reading Mr. Basildon’s solution that I don’t know the difference between Seq, List, etc. and when it matters. Maybe it’s just that seq can be infinite, vs. List is strictly an actual memory block?&lt;/p&gt;</description><link>http://blog.learnr.org/post/34614520</link><guid>http://blog.learnr.org/post/34614520</guid><pubDate>Mon, 12 May 2008 21:15:00 -0700</pubDate></item></channel></rss>
