The First Scaling Theory

How a mind scales when the interpreter can evaluate

PDF version

The claim. Work scales as evaluation. Write it as math — terms, equations, substitution that preserves meaning — and run it on a runtime: agent, record, checks. Scale is then specification quality, not headcount.

That is the breakthrough. It is already running. A stranger can check it; they do not have to take an opinion. The commercial name is compliance that compiles.

The unit is not a company and not an industry. It is an endeavor — a firm, a case, a raise, a move, a life’s work. Wherever the substance is bits, paper, money, or law, the method is the same.

Scaling through people is the historical default. That is not a theory. It is what you do when the interpreter cannot evaluate.

The Quantum Threat

The intersection point on this graph is the end of the world as we know it. The security of the internet based on existing cryptography that we’ve had since day one will be permanently over.

Military, banking, private messaging, identity, medical and legal records all exposed. Only post-quantum encryption algorithms will save us.

Still no solid plan for this from any major corporation or institution let alone any government.

Unsolved P vs. NP problem no longer even matters.

Go is Korean, Lisp is Japanese

Recently I took a fresh at look at the Go programming language after having last taken a look at it before version 1.0 was released back in 2009. What I’ve found in just a few days is shocking in a really really good way.

Lesser Known Origins Of The Technical Interview

The questionable widespread technical interview process has it’s roots in a cold war era approach that was pioneered by a public proponent of eugenics. Minorities suffer the most from the industry continuing to use this long disproved ritual of conformity.

Dear recruiter - a canned response to a canned email

Sep 9, 2021

First, thank you for reaching out. People like you help other people make a living by matching them with companies and opportunities.

If you got a link to this post from me that means that I read your email and find it irrelevant for my profile. This is usually the case because:

  • Your role does not fit my experience. In many of my roles I led a team of engineers, managers and product managers. Is the scope you offer me similar? How do you think that being a front-end engineer in your team matches my current level and experience?
  • Your compensation is off. If you are trying to recruit top talent from a FAANG company you should be aware about their compensation expectations. Levels.fyi can give you an idea of what is expected in each level. Can this company offer a similar (or higher) pay to L6-7/M1-2 on Facebook/Google/Amazon? Also, while I’m sure your startup is about to take over the world- I’m not looking to get paid in virtual money stocks.
  • I don’t do meetings My time is important. Yours too. Time is the only currency we have. From reading your message I can see that there’s a low chance for a match so let’s save time and skip the meeting.

How can you do better next time? Invest more in research before reaching out. Spend most of your time on it. Don’t send generic messages to every engineer in your LinkedIn filter list. First, it will probably piss them off, second you will end up in the spam folder. Read about each potential candidate, evaluate their experience and only if you’re 80% sure there’s a match send them an email. The email should be catered towards their experience, showing how it can match this new role. Also do some homework on compensation and make sure the company can match the pay for the talent you are targeting. I do believe that a personalized message will get you a better response rate with the candidates you approach. Even if it will not be a fit, you will establish a good relationship with them. This can be very useful for the future.

Some thoughts on consensus algorithms for blockchains

Most #ShitCoin consensus algorithms are based on Proof Of Stake. This is no coincidence. This allows for centralized control of what are essentially just digital fiat currencies and enable the same fraud we’ve seen in most economies that have their paper fiat currency gamed by banks and government.

The loudest voices on blockchain tech know the least. Proof Of Stake chains rest on circular logic fallacies and a misunderstanding of fungibility and forks. Fatal flaws that will not be fixed by rearranging security deposits. The deck chairs on the Titanic were very neatly organized.

Hello Immortal World with Rust

Bastion is a highly-available, fault-tolerant runtime system with dynamic dispatch oriented lightweight process model.

Features

  • Message-based communication makes this project a lean mesh of actor system.
    • Without web servers, weird shenanigans, forced trait implementations, and static dispatch.
  • Runtime fault-tolerance makes it a good candidate for distributed systems.
    • If you want the smell of Erlang and the powerful aspects of Rust. That’s it!
  • Completely asynchronous runtime with NUMA-aware and cache-affine SMP executor.
    • Exploiting hardware locality wherever it is possible. It is designed for servers.
  • Supervision system makes it easy to manage lifecycles.
    • Kill your application in certain condition or restart you subprocesses whenever a certain condition is met.

Guarantees

  • At most once delivery for all the messages.
  • Completely asynchronous system design.
  • Asynchronous program boundaries with fort.
  • Dynamic supervision of supervisors (adding a subtree later during the execution)
  • Lifecycle management both at futures and lightproc layers.
  • Faster middleware development.
  • Above all “fault-tolerance”.
jgrant27/hello-immortal-world
Rust immortal (un-panic-able) “Hello World” example using bastion/fort - jgrant27/hello-immortal-world

The Golden 20s

The Golden 20s of the 20th century began with the end of WW1 and ended with the stock market crash of 1929. It was considered the decade that was the calm before the storm. However, it was a decade of sweeping technological change and innovation that transformed industrial productivity, life in general and in turn the world economy. It improved the general well-being of many. Electricity, the internal combustion engine and radio changed everyday life forever.Still, a lot has changed in a hundred years since then. The invention of the transistor happened over 70 years ago and the Internet has been in the mainstream for 25 years now. Commodity cloud computing has been around for over 15 years, thanks AWS. Looking back at the 2010s though there have not been any earth-shattering technological inventions. Don’t get me wrong, there have been numerous incredible improvements to existing technology in cost, speed and pervasiveness. The focus has been more horizontal than vertical. My predictions for the 20s are that we are going to see some major changes technologically. Why ? There are just too many forcing functions that can no longer be ignored in the tech industry. Corporations that sell user data, corporations that ignore data security are all losing market share and quickly at that. Internet-enabled cyber-crime estimates from the FBI put the growing cost at around $10 billion for the 2010s and that number will only continue to rise. The rapid growth of IoT devices compounds this issue.

When will Rust be formally specified ?

The sooner a language is formally specified and standardized the better. I don’t want to see Rust go the way of languages like Ruby(which eventually got a spec) or Clojure (still does not have one). Without this and the longer it’s delayed, external libraries spring up to solve problems that should be fully or partially addressed in the core of the language. A formal language spec along with standardization would also potentially inform much higher quality crate design while also allowing quicker progress on many fronts due to less ambiguity. It also would allow for multiple tool-chain implementations e.g. compilers.

Error handling or The Emperor's Old Clothes.

TLDR; This problem has been solved for 40 years but the software development industry is still very fashion-oriented.

In both Common Lisp and Smalltalk error handlers can resume the computation that raised it, restart it, or refuse to handle it while the error handling code itself can be separated out from where it is caught i.e. into re-usable functions. Without unwinding the stack and losing the context of why/where the error occurred.

Everyday Ada : Simple REST Service

Ada (previously) is a time-tested, safe, secure programming software-engineering language with a 40-year record of success in mission-critical applications such as…

  • Air Traffic Management Systems

  • Desktop and Web Applications

  • Commercial Aviation

  • Banking and Financial Systems

  • Railway Transportation

  • Information Systems

  • Commercial Rockets

  • Commercial Shipboard Control Systems

  • Commercial Imaging Space Vehicles

  • Television/Entertainment Industry

  • Communication and Navigational Satellites and Receivers

  • Medical Industry

  • Data Communications

  • General Industry

  • Scientific Space Vehicles

  • Military Applications

How good is Ada though for something that most programmers might work on in their day to day ? Something like building a REST service ? Well here’s the hello-world of a REST service in Ada.

Raspberry Pi 4

The Raspberry Pi 4 is a leap forward not just for the Pi but for single-board computers across the board. It’s a great light-weight desktop replacement. It’s even surprised me as a viable Rust / Ada development environment.

@@HOLD0@@

My setup includes a Raspberry Pi 4 FLIRC case which is basically a giant aluminum heat sink. This allows for a completely silent setup running at an average of 54’C. During extended code-compiles that tops out around 65’C which is more than enough cooling and completely worth the silence when compared with a fan.

Ada, Rust and Steelman language requirements

Ada is the only pragmatic language that is still growing in a healthy way that meets the Steelman language requirements (created by US DoD circa 1978). Ada is rare among programming languages in that it is one of the few that was designed up-front according to a years-long well defined specification. Rust, at least aspires to meeting some of these requirements, even if not intentionally.

*Crucial in the Steelman requirements were: *

    • A general, flexible design that adapts to satisfy the needs of embedded computer applications.*
  • Reliability*. The language should aid the design and development of reliable programs.*

Signal Desktop for Arm/Linux

As I’ve been spending a lot of time with Arm hardware lately as my primary desktop and server platform I missed using my secure messenger app of choice. I was able to cook up builds for both armv7l/armhf/GNU Linux (32-bit) and arm64/aarch64/GNU Linux (64-bit).

These are unofficial but fully working builds of Signal Desktop for Linux on Arm processors. Enjoy !

[Signal Desktop armv7l/armhf/GNU Linux](/files/signal-desktop-arm/signal-desktop-linux-armv7l.zip)

[Signal Desktop arm64/aarch64/GNU Linux](/files/signal-desktop-arm/signal-desktop-linux-arm64.zip)

armv71_desktop

Two sorts with Rust

Here are some initial thoughts on Rust in the almost two years since I last looked at it along with some implementations of merge and quick sort. (These are just my opinions so please don’t panic !)

  1. Cargo is awesome for managing package dependencies and building projects.

  2. Rust is a very nice systems programming language that supports a functional style of programming. Much easier to work with than C/C++ with very near the same performance in many cases.

Ring probabilities in F#

A few months back I took a look at Elixir. More recently I’ve been exploring F# and I’m very pleased with the experience so far. Here is the ring probabilities algorithm implemented using F#. It’s unlikely that I will ever use Elixir again because having a powerful static type system provided by F# at my disposal is just too good.

let rec calcStateProbs (prob: float, i: int,
                        currProbs: float [], newProbs: float []) =
  if i < 0 then
    newProbs
  else
    let maxIndex = currProbs.Length-1
    // Match prev, next probs based on the fact that this is a
    // ring structure.
    let (prevProb, nextProb) =
      match i with
        | i when i = maxIndex -> (currProbs.[i-1], currProbs.[0])
        | 0 -> (currProbs.[maxIndex], currProbs.[i+1])
        | _ -> (currProbs.[i-1], currProbs.[i+1])
    let newProb = prob * prevProb + (1.0 - prob) * nextProb
    Array.set newProbs i newProb
    calcStateProbs(prob, i-1, currProbs, newProbs)
let calcRingProbs parsedArgs =
  // Probs at S = 0.
  //   Make certain that we are positioned at only start location.
  //     e.g. P(Start Node) = 1
  let startProbs =
    Array.concat [ [| 1.0 |] ; [| for _ in 1 .. parsedArgs.nodes - 1 -> 0.0 |] ]
  let endProbs =
    List.fold (fun probs _ ->
               calcStateProbs(parsedArgs.probability, probs.Length-1,
                              probs, Array.create probs.Length 0.0))
              startProbs [1..parsedArgs.states]
  endProbs

Here’s the code.

Ring probabilities with Elixir

I’ve been hearing more about Elixir lately so I thought I’d take it for a spin.

*“Elixir is a functional, meta-programming aware language built on top of the Erlang VM. It is a dynamic language that focuses on tooling to leverage Erlang’s abilities to build concurrent, distributed and fault-tolerant applications with hot code upgrades.”

I’ve never really spent any time with Erlang but always been curious about it and the fact that it’s one of the best kept ‘secrets’ in many startups these days. I’ve heard for years how easy it is to ‘scale out’ compared with many other languages and platforms.

Corporate funding for Shen

cai_shen

It looks like it might be coming sooner than I thought. I’m sure Shenturions everywhere will find this news incredibly exciting for the future of Shen. I can’t wait to see how things progress.

Purely Functional Data Structures & Algorithms : Selection Sort

Updated @ 2012-08-31 02:08:58 due to internet pedantry

Previously, previously.

According to Wikipedia :

In computer science, a Selection sort is a sorting algorithm, specifically an in-place comparison sort. It has O(n2) time complexity, making it inefficient on large lists, and generally performs worse than the similar insertion sort. Selection sort is noted for its simplicity, and also has performance advantages over more complicated algorithms in certain situations, particularly where auxiliary memory is limited.

(A functional implementation of selection sort is however, not an in-place sort.)

Purely Functional Data Structures & Algorithms : Union-Find (Haskell)

Updated 08-23-2012 01:04:38

Replaced the use of Data.Vector with the persistent Data.Sequence which has O(logN) worst case time complexity on updates.

A Haskell version of the previous code using the more efficient(access and update) persistent Data.Sequence type so that the desired time complexity is maintained for the union operation.

-- Disjoint set data type (weighted and using path compression).
-- O((M+N)lg*N + 2MlogN) worst-case union time (practically O(1))
-- For M union operations on a set of N elements.
-- O((M+N)lg*N) worst-case find time (practically O(1))
-- For M connected(find) operations on a set of N elements.
data DisjointSet = DisjointSet
     { count :: Int, ids :: (Seq Int), sizes :: (Seq Int) }
     deriving (Read,  Show)
-- Return id of root object
findRoot :: DisjointSet -> Int -> Int
findRoot set p | p == parent = p
               | otherwise   = findRoot set parent
               where
                parent = index (ids set) (p - 1)
-- Are objects P and Q connected ?
connected :: DisjointSet -> Int -> Int -> Bool
connected set p q = (findRoot set p) == (findRoot set q)
-- Replace sets containing P and Q with their union
quickUnion :: DisjointSet -> Int -> Int -> DisjointSet
quickUnion set p q | i == j = set
                   | otherwise = DisjointSet cnt rids rsizes
                     where
                        (i, j)   = (findRoot set p, findRoot set q)
                        (i1, j1) = (index (sizes set) (i - 1), index (sizes set) (j - 1))
                        (cnt, psmaller, size) = (count set - 1, i1 < j1, i1 + j1)
                        -- Always make smaller root point to the larger one
                        (rids, rsizes) = if psmaller
                                         then (update (i - 1) j (ids set), update (j - 1) size (sizes set))
                                         else (update (j - 1) i (ids set), update (i - 1) size (sizes set))

Tested …

Purely Functional Data Structures & Algorithms : Union-Find

It’s been a while since I last posted in this series. Today we look at the disjoint-set data structure, specifically disjoint-set forests and the complementary algorithm : union-find.

In computing, a disjoint-set data structure is a data structure that keeps track of a set of elements partitioned into a number of disjoint (nonoverlapping) subsets. A union-find algorithm is an algorithm that performs two useful operations on such a data structure:

  • Find: Determine which subset a particular element is in. This can be used for determining if two elements are in the same subset.

Codebreaker - A new film about the life of Alan Turing

CODEBREAKER tells the story of one of the most important people of the 20th century. Alan Turing set in motion the computer age and his World War II codebreaking helped save two million lives. Yet few people have heard his name, know his tragic story, or understand his legacy. In 1954, Turing committed suicide at age 41 after being forced to undergo hormone therapy to “fix” his sexual orientation. He left behind a lasting legacy and lingering questions about what else he might have accomplished if society had embraced his unique genius instead of rejecting it. 100 years after his birth, an international production team takes viewers on a journey to rediscover the man and the mystery.

Bayes's Theorem is more powerful than Jesus

Richard Carrier puts forward a fantastic approach to verifying history in his latest book :

Proving History: Bayes’s Theorem and the Quest for the Historical Jesus

“… historian Richard C. Carrier proposes Bayes’s theorem as a solution to the problem of establishing reliable historical criteria. He demonstrates that valid historical methods—not only in the study of Christian origins but in any historical study—can be described by, and reduced to, the logic of Bayes’s theorem. Conversely, he argues that any method that cannot be reduced to Bayes’s theorem is invalid and should be abandoned.”

Alan Kay on Programming today (and a few other things)

From a recent Dr. Dobbs interview :

On adults –

Binstock: So you called them on the lying.

Kay: Yeah. But the thing that traumatized me occurred a couple years later, when I found an old copy of Life magazine that had the Margaret Bourke-White photos from Buchenwald. This was in the 1940s — no TV, living on a farm. That’s when I realized that adults were dangerous. Like, really dangerous.

The lack of interest, the disdain for history is what makes computing not-quite-a-field.

Moore's Law is "dead"

Exhibit A, My 11″ MacBook Air (Late 2010) benchmark rating :

Exhibit B, My 11″ MacBook Air (Mid 2012) benchmark rating :

Spring 2012 books

For the New Intellectual: The Philosophy of Ayn Rand (50th Anniversary Edition) – Ayn Rand

This is Ayn Rand’s challenge to the prevalent philosophical doctrines of our time and the “atmosphere of guilt, of panic, of despair, of boredom, and of all-pervasive evasion” that they create. One of the most controversial figures on the intellectual scene, Ayn Rand was the proponent of a moral philosophy–and ethic of rational self-interest–that stands in sharp opposition to the ethics of altruism and self-sacrifice. The fundamentals of this morality–“a philosophy for living on Earth”–are here vibrantly set forth by the spokesman for a new class, For the New Intellectual.

Computers for Cynics

Ted Nelson‘s latest video series called “Computers for Cynics” calls it like it is. How refreshing in contrast with the pervasive garbage called ‘information’ that we get fed in the second decade of the 21st century.

I laughed and wept at part 1 : The Myth of Technology

Quite timely considering the recent round of UI design atrocities spread under the mask of ‘good design’.

As if a bunch of over-payed(Windows), over-stroked(Gnome), over-controlling(Mac) middle-managed programmers can do what Steve Jobs did.

Cognitive Robotics And Artificial Intelligence

Eccerobot
Eccerobot
At the [swissnex San Francisco](http://swissnexsanfrancisco.org//) conference earlier this year, scientists from Switzerland and the US discussed their research on humanoid robots, cognitive robotics, and artificial intelligence (AI). Talk revolved around how some robots self-reflect, self-improve, and adapt to new circumstances, and whether it’s possible for robots of the future to possess the same cognitive characteristics as humans.

more …

Chronicle

Chronicle has to be the best sci-fi movie I’ve seen in 2012.

Shot in Cape Town, South Africa on a budget of just $15 million. The end result is incredible including it’s box-office results.

Hope the sequel is just as good.

Experimental change

So I’ve switched this blog to WP for now. There are still some formatting issues here and there so please be patient while they are fixed.

Comments have been enabled for all posts retroactively.

Let’s see how this goes …

Welcome to John McCarthy's new website.

From the website: John was a legendary computer scientist at Stanford University who developed time-sharing, invented LISP, and founded the field of Artificial Intelligence.* In March 2011 John launched Project JMC with the objective to make his work more approachable and accessible. The Project JMC team is continuing to help realize his objective. In this site you will find all John’s work, including his social commentary, and acknowledgements of his outstanding contributions and impact. Additional comments, suggestions, stories, photographs and videos on John and his work are very welcome. Please send them to the Project JMC team. His old website is here.

Quick Sort in Shen

A Shen type-checked implementation of Quick Sort is even more elegant/terse compared with the CL version posted previously.

Pattern-matching and currying make this possible.

(tc +)
(define filter
  {(A --> boolean) --> (list A) --> (list A)}
  _  []      -> []
  T? [A | B] -> (append [A] (filter T? B)) where (T? A)
  T? [_ | B] -> (filter T? B))
(define quick-sort-generic
  {(list A) --> (A --> A --> boolean) --> (A --> A --> boolean) --> (list A)}
  [] _ _ -> []
  [A | B] L? R? -> (append (quick-sort-generic (filter (R? A) B) L? R?)
			   [A]
			   (quick-sort-generic (filter (L? A) B) L? R?)))
\* descending with duplicates *\
* (quick-sort-generic [3 1 2 7 9 6 6 3 0] >= <)
* [9 7 6 6 3 3 2 1 0] : (list number)

The complete code can be found here. Based on this numeric version.

Quick Sort in Common Lisp

After watching some of Tim Roughgarden’s videos on sorting algorithms, I thought I’d post an implementation of quick sort in Common Lisp as an example of a sorting algorithm implemented in CL. It’s a simple enough example(at < 20 LOC) that demonstrates one non-imperative approach to algorithm implementation. The complete code can be found here.

(defun quick-sort-generic2 (sequence cfun &optional result-type)
  (if (<= (length sequence) 1)
      (copy-seq sequence)
      (flet ((partition (fun array)
           (list (remove-if-not fun array) (remove-if fun array))))
    (let* ((result-type (or result-type 'vector))
           (pivot-ind (random (length sequence)))
           (pivot-val (elt sequence pivot-ind))
           (rem-seq
        (remove pivot-val sequence :start pivot-ind :end (+ 1 pivot-ind)))
           (part (partition (lambda (x)
                  (apply cfun (list x pivot-val))) rem-seq)))
      (concatenate result-type
               (quick-sort-generic2 (car part) cfun result-type)
               (list pivot-val)
               (quick-sort-generic2 (cadr part) cfun result-type))))))
* (test-sort)
started quick-sort (generic, array) ...
Evaluation took:
  0.089 seconds of real time
  0.081912 seconds of total run time (0.081587 user, 0.000325 system)
  92.13% CPU
  142,664,472 processor cycles
  8,375,024 bytes consed
quick-sorted 10000 items (first 10 shown) :
#(9998 9998 9998 9997 9997 9996 9995 9994 9993 9992)
started quick-sort (generic, list) ...
Evaluation took:
  0.062 seconds of real time
  0.058722 seconds of total run time (0.058417 user, 0.000305 system)
  95.16% CPU
  99,419,648 processor cycles
  9,371,456 bytes consed
quick-sorted 10000 items (first 10 shown) :
(9999 9998 9997 9997 9996 9996 9994 9993 9993 9992)

Happy Pi Day in Shen

Here’s a port of the previous Qi II code to Shen.

Run with Hakan Raberg’s 0.1.4 version of shen.clj (Shen implemented in Clojure !).

*
  Accurately calculates N digits of Pi using Machin's formula
  with fixed point arithmetic and variable guards digits.
  Depends on the maths library -->
    http://www.shenlanguage.org/library.html
*
(tc +)
(define arccot-
  {number --> number --> number --> number --> number --> number}
  X N XPOWER    0 _ -> 0
  X N XPOWER TERM 1 -> (+ (arccot- X (+ N 2) (floor (/ XPOWER X))
                                     (floor (/ XPOWER N)) 0)
                          (floor (/ XPOWER N)))
  X N XPOWER TERM 0 -> (- (arccot- X (+ N 2) (floor (/ XPOWER X))
                                      (floor (/ XPOWER N)) 1)
                          (floor (/ XPOWER N))))
(define arccot
  {number --> number --> number}
  X UNITY -> (let XPOWER (floor (/ UNITY X))
                  (arccot- (* X X) 1 XPOWER (floor XPOWER) 1)))
(define machin-pi
  {number --> number}
  DIGITS -> (let GUARD (+ 10 (ceiling (log' DIGITS 10)))
                 UNITY (expt 10 (+ DIGITS GUARD))
                 (floor (/ (* 4 (- (* 4 (arccot 5 UNITY))
                                   (arccot 239 UNITY)))
                           (expt 10 GUARD)))))
(1+) (time (machin-pi 100))
run time: 2.56899999999996 secs
31415926535...4350265344N : number

Robot readable world

How do robots see the world? How do they gather meaning from our streets, cities, media and from us?

This is an experiment in found machine-vision footage, exploring the aesthetics of the robot eye.

Hey kids, just say NO to programming !

Cory Doctorow’s latest talk ‘The Coming War on General Purpose Computing’ really puts things in perspective about life in the 21st century.

This got me thinking more about functional programming languages and how they could be a future casualty in a similar way that we currently see the intentional limitation/crippling of turing machines.

What if Paul Graham missed something very dark in his essay The Hundred-Year Language ?

Clojure/Conj 2011

Sold out attendance marked this being the second premiere conference for Clojure. What I realized is just how great the people are in this community. No, seriously. There’s far less ego than with many other communities. This is a great sign for the future of Clojure. Particularly because Rich is such a great guy. He even gave a public apology for something or other that he said(on a mailing list) which he felt was not in the spirit of the Clojure community.

Overtone

Overtone is an open source audio environment being created to explore musical ideas from synthesis and sampling to instrument building, live-coding and collaborative jamming.

In this video Sam Aaron gives a fast-paced introduction to a number of key live programming techniques such as triggering instruments, scheduling future events and synth design. Finally, the viewer is shown how a simple musical sequence may be composed and then converted into an intricate Reich phase. The main body of the video was recorded in one take and features an Emacs buffer (using the Live Coding Config (is.gd/​live_coding_emacs) for editing text and communicating with Overtone (is.gd/​overtone), an expressive Clojure front-end to SuperCollider. Clojure is a state-of-the-art functional lisp emphasising immutability and concurrency (clojure.org).

Shen/Kl arrive

The first publicly available version of Shen/Kl has been released.

The Shen mission is to develop an ultra-portable version of Qi that can run under a wide variety of platforms and which incorporates missing features in Qi such as streams. The targeted platforms are CL, Clojure, NewLisp, Emacs Lisp, ECL, Scheme, Javascript and Python as well as C/C++, DVM, CLR or the JVM. This approach involved rewriting and redesigning Qi to fit within the smallest feasible instruction set.

ClojureScript Demo : Convex Hull

Update : bug-fix when hull was being incorrectly calculated due to there being duplicate points generated in the random set.

ClojureScript looks like a solid approach to building applications that target JavaScript VMs. It’s built on top of Google’s Closure Compiler/Library which is very intruiging and is the best approach that they could have taken (now that I’ve a played with it a little). Being new to both Closure and ClojureScript I was curious about what it might feel like to build an application using these tools. I’ve mostly despised programming in JavaScript for browsers no matter what hyped-up library is available (this includes JQuery which is the best of a bad bunch in my opinion). So I decided to write a ClojureScript application that runs in the browser based on a previous Clojure implementation of a Convex Hull algorithm with heuristics.

Purely Functional Data Structures & Algorithms : Fast Fourier Transform in Qi

In this second post in this series we look at an implementation of the always useful Fast Fourier Transform.

(FFT) An algorithm for computing the Fourier transform of a set of discrete data values. Given a finite set of data points, for example a periodic sampling taken from a real-world signal, the FFT expresses the data in terms of its component frequencies. It also solves the essentially identical inverse problem of reconstructing a signal from the frequency data.

Purely Functional Data Structures & Algorithms : Red-Black Trees in Qi

Update 2011/06/28 : Source has been modified to compile with Shen

This is the first in a series of posts that will demonstrate the implementation of many well-known(and less known) data structures and algorithms using a purely functional approach.

We will use Qi as our implementation language for a number of reasons :

It’s a Lisp : macros, EVAL, hash-tables, property-lists, meta-programming etc.

Pattern matching.

Optional static type checking.

A Turing-complete type system !

Spring/Summer 2011 Books

Marvin Minksy’s – The Emotion Machine: Commonsense Thinking, Artificial Intelligence, and the Future of the Human Mind

Minsky argues that emotions are different ways to think that our mind uses to increase our intelligence. He challenges the distinction between emotions and other kinds of thinking. His main argument is that emotions are “ways to think” for different “problem types” that exist in the world. The brain has rule-based mechanism (selectors) that turns on emotions to deal with various problems. The book reviews the accomplishments of AI, what and why is complicated to accomplish in terms of modeling how human beings behave, how they think, how they experience struggles and pleasures. (Wikipedia)

Happy PI day ! (in QiII)

Qi is the future of Lisp.

It is Lisp with many great features such as pattern-matching, a turing complete static type system (even more powerful than Haskell’s type system) and many others.

So in the spirit of PI day, here’s an implementation that calculates PI using Machin’s formula.

(define ceiling
  X -> (CEILING X))
(declare ceiling [number --> number])
(define expt
  X Y -> (EXPT X Y))
(declare expt [number --> number --> number])
(define floor
  X Y -> (FLOOR X Y))
(declare floor [number --> number --> number])
(define log
  X Y -> (LOG X Y))
(declare log [number --> number --> number])
(tc +)
(define arccot-
  {number --> number --> number --> number --> number --> number}
  X N XPOWER    0 _ -> 0
  X N XPOWER TERM 1 -> (+ (arccot- X (+ N 2) (floor XPOWER X)
                                     (floor XPOWER N) 0) (floor XPOWER N))
  X N XPOWER TERM 0 -> (- (arccot- X (+ N 2) (floor XPOWER X)
                                      (floor XPOWER N) 1) (floor XPOWER N)))
(define arccot
  {number --> number --> number}
  X UNITY -> (let XPOWER (floor (/ UNITY X) 1)
                  (arccot- (* X X) 1 XPOWER (floor XPOWER 1) 1)))
(define machin-pi
  {number --> number}
  DIGITS -> (let GUARD (+ 10 (ceiling (log DIGITS 10)))
                 UNITY (expt 10 (+ DIGITS GUARD))
                 (floor (* 4 (- (* 4 (arccot 5 UNITY))
                                (arccot 239 UNITY))) (expt 10 GUARD))))

And the output …

Philosophy and Lisp

Programming language wars don’t have to be religious based wars. Programming languages should be rooted in philosophy. The more a programming language is rooted in sound philosophy the more value it has.

Over the years, many of the posts on this blog have been regarding some programming language, algorithm or technology. Some posts have highlighted why Lisp is the most powerful and useful programming language paradigm available to man at this point in the history of computer science.

Artificial Intuition

Artificial Intuition – A New Possible Path To Artificial Intelligence – by Monica Anderson

Artificial Intelligence was born in Computer Science departments, and inherited their value sets including Correctness. This mindset, this necessity to be logical, provable, and correct has been a fatal roadblock for Artificial Intelligence since its inception. The world is Bizarre, and Logic can not describe it. Artificial Intuition will easily outperform Logic based Artificial Intelligence for almost any problem in a Bizarre problem domain. From the very beginning, Artificial Intelligence should have been a soft science.

Anaphoric(aka "Un-hygenic") macros in CL

As an example let’s look at an algorithm that’s fairly common : breadth first traversal of a binary tree. Also called level-order traversal.

Wikipedia:

“In graph theory, breadth-first search (BFS) is a graph search algorithm that begins at the root node and explores all the neighboring nodes. Then for each of those nearest nodes, it explores their unexplored neighbor nodes, and so on, until it finds the goal.”

First let’s define a simple node struct and create a tree :

Ruby compiler in CL

The implementers of existing Ruby VMs have gone the way of C, C++ and Java. There is another possibility. Why not implement Ruby in Common Lisp ?

Ok, let’s take the first shot and implement a subset of the Ruby language. Just enough to run some simple contrived numeric benchmarks. The following pseudo BNF describing a minimal subset of Ruby should do (taken from the rubydocs here).

PROGRAM         : COMPSTMT
COMPSTMT        : STMT (TERM EXPR)* [TERM]
STMT            : CALL
| EXPR
EXPR            | ARG
CALL            : FUNCTION
FUNCTION        : OPERATION [`(' [CALL_ARGS] `)']
ARG             : LHS `=' ARG
| ARG `..' ARG
| ARG `+' ARG
| ARG `-' ARG
| ARG `*' ARG
| PRIMARY
PRIMARY         : LITERAL
| VARIABLE
| for BLOCK_VAR in EXPR DO
COMPSTMT
end
| def FNAME ARGDECL
COMPSTMT
end
LHS             : VARIABLE
CALL_ARGS       : ARGS
ARGS            : ARG (`,' ARG)*
ARGDECL         : `(' ARGLIST `)'
ARGLIST         : IDENTIFIER(`,'IDENTIFIER)*
VARIABLE        : VARNAME
| nil
LITERAL         : numeric
| STRING
TERM            : `;'
| `n'
FNAME           : IDENTIFIER
OPERATION       : IDENTIFIER
VARNAME         : IDENTIFIER
STRING          : `"' any_char* `"'
IDENTIFIER is the sequence of characters in the pattern of /[a-zA-Z_][a-zA-Z0-9_]*/.

Let’s write two functions in our new Ruby subset language. First a function to calculate fibonacci numbers.

Facts about STM

These days there just can’t be enough said to counter the hype that comes with STM. The following paper is an eye opening read(it measures actual peformance of STM). Hopefully some of the STM faithful will re-consider their fanatic beliefs.

Software transactional memory: why is it only a research toy?

“In this article, we explore the performance of a highly optimized STM and observe the overall performance of TM is much worse at low levels of parallelism, which is likely to limit the adoption of this programming paradigm.”

π in assembly (spigot algorithm)

//   pi_spigot.s - calculates Pi using a spigot algorithm
//                 as an array of n digits in base 10000.
//                 http://mathworld.wolfram.com/SpigotAlgorithm.html
//
//  x86-64/SSE3 with for Linux, Intel, gnu assembler, gcc
//
//  assemble: as pi_spigot.s -o pi_spigot.o
//  link:     gcc -o pi_spigot pi_spigot.o
//  example run:      ./pi_spigot 100
//  output: 3.14159265358979323846264338327950288419716939937510582097494459230 ...
//        ... 78164062862089986280348253421170679
//
    .section    .rodata
.LC0:
    .string "%d."
.LC1:
    .string "%04d"
    .text
.globl print
    .type   print, @function
print:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    subq    $32, %rsp
    movq    %rdi, -24(%rbp)
    movl    %esi, -28(%rbp)
    movq    -24(%rbp), %rax
    addq    $2, %rax
    movzwl  (%rax), %eax
    movzwl  %ax, %edx
    movl    $.LC0, %eax
    movl    %edx, %esi
    movq    %rax, %rdi
    movl    $0, %eax
    call    printf
    movl    $2, -4(%rbp)
    jmp .L2
.L3:
    movl    -4(%rbp), %eax
    cltq
    addq    %rax, %rax
    addq    -24(%rbp), %rax
    movzwl  (%rax), %eax
    movzwl  %ax, %edx
    movl    $.LC1, %eax
    movl    %edx, %esi
    movq    %rax, %rdi
    movl    $0, %eax
    call    printf
    addl    $1, -4(%rbp)
.L2:
    movl    -28(%rbp), %eax
    subl    $1, %eax
    cmpl    -4(%rbp), %eax
    jg  .L3
    movl    $10, %edi
    call    putchar
    leave
    ret
    .cfi_endproc
.LFE0:
    .size   print, .-print
.globl main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $56, %rsp
    movl    %edi, -52(%rbp)
    movq    %rsi, -64(%rbp)
    cmpl    $1, -52(%rbp)
    jle .L6
    .cfi_offset 3, -24
    movq    -64(%rbp), %rax
    addq    $8, %rax
    movq    (%rax), %rax
    movq    %rax, %rdi
    call    atoi
    addl    $3, %eax
    leal    3(%rax), %edx
    testl   %eax, %eax
    cmovs   %edx, %eax
    sarl    $2, %eax
    addl    $3, %eax
    jmp .L7
.L6:
    movl    $253, %eax
.L7:
    movl    %eax, -20(%rbp)
    movl    -20(%rbp), %eax
    cltq
    addq    %rax, %rax
    movq    %rax, %rdi
    call    malloc
    movq    %rax, -40(%rbp)
    movl    -20(%rbp), %eax
    cltq
    leaq    (%rax,%rax), %rdx
    movq    -40(%rbp), %rax
    movl    $0, %esi
    movq    %rax, %rdi
    call    memset
    movq    -40(%rbp), %rax
    addq    $2, %rax
    movw    $4, (%rax)
    cvtsi2sd    -20(%rbp), %xmm0
    movsd   .LC2(%rip), %xmm1
    mulsd   %xmm1, %xmm0
    cvttsd2si   %xmm0, %eax
    movl    %eax, -24(%rbp)
    jmp .L8
.L13:
    movl    $0, -32(%rbp)
    movl    -20(%rbp), %eax
    subl    $1, %eax
    movl    %eax, -28(%rbp)
    jmp .L9
.L10:
    movl    -28(%rbp), %eax
    cltq
    addq    %rax, %rax
    addq    -40(%rbp), %rax
    movzwl  (%rax), %eax
    movzwl  %ax, %eax
    imull   -24(%rbp), %eax
    addl    %eax, -32(%rbp)
    movl    -28(%rbp), %eax
    cltq
    addq    %rax, %rax
    movq    %rax, %rbx
    addq    -40(%rbp), %rbx
    movl    -32(%rbp), %ecx
    movl    $1759218605, %edx
    movl    %ecx, %eax
    imull   %edx
    sarl    $12, %edx
    movl    %ecx, %eax
    sarl    $31, %eax
    movl    %edx, %esi
    subl    %eax, %esi
    movl    %esi, %eax
    imull   $10000, %eax, %eax
    movl    %ecx, %edx
    subl    %eax, %edx
    movl    %edx, %eax
    movw    %ax, (%rbx)
    movl    -32(%rbp), %ecx
    movl    $1759218605, %edx
    movl    %ecx, %eax
    imull   %edx
    sarl    $12, %edx
    movl    %ecx, %eax
    sarl    $31, %eax
    movl    %edx, %ecx
    subl    %eax, %ecx
    movl    %ecx, %eax
    movl    %eax, -32(%rbp)
    subl    $1, -28(%rbp)
.L9:
    cmpl    $0, -28(%rbp)
    jns .L10
    movl    $0, -44(%rbp)
    movl    -44(%rbp), %eax
    movl    %eax, -48(%rbp)
    movl    $0, -28(%rbp)
    jmp .L11
.L12:
    movl    -24(%rbp), %eax
    addl    %eax, %eax
    leal    1(%rax), %edx
    movl    -28(%rbp), %eax
    cltq
    addq    %rax, %rax
    addq    -40(%rbp), %rax
    movzwl  (%rax), %eax
    movzwl  %ax, %ecx
    movl    -44(%rbp), %eax
    imull   $10000, %eax, %eax
    leal    (%rcx,%rax), %eax
    movl    %edx, %esi
    movl    %eax, %edi
    call    div
    movq    %rax, -48(%rbp)
    movl    -28(%rbp), %eax
    cltq
    addq    %rax, %rax
    addq    -40(%rbp), %rax
    movl    -48(%rbp), %edx
    movw    %dx, (%rax)
    addl    $1, -28(%rbp)
.L11:
    movl    -28(%rbp), %eax
    cmpl    -20(%rbp), %eax
    jl  .L12
    movq    -40(%rbp), %rax
    addq    $2, %rax
    movq    -40(%rbp), %rdx
    addq    $2, %rdx
    movzwl  (%rdx), %edx
    addl    $2, %edx
    movw    %dx, (%rax)
    subl    $1, -24(%rbp)
.L8:
    cmpl    $0, -24(%rbp)
    jg  .L13
    movl    -20(%rbp), %edx
    movq    -40(%rbp), %rax
    movl    %edx, %esi
    movq    %rax, %rdi
    call    print
    movl    $0, %eax
    addq    $56, %rsp
    popq    %rbx
    leave
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .section    .rodata
    .align 8
.LC2:
    .long   3161095930
    .long   1076532084

Google to acquire ITA ?

Update 2010-06-30 : So just over a day after I posted this entry Google announced that they have acquired ITA. Announcement

There was buzz back in April about Google possibly acquiring ITA Software.

A few days ago Dan posted that these were just rumors based on a single Bloomberg article.

Well it seems that it may be more than just a rumor : The Wall Street journal now has an article regarding the potential acquisition.

Summer 2010 reading

“Let over Lambda – 50 Years of Lisp” by Doug Hoyte

This one had been sitting on my bookshelf for almost a year.

“Let Over Lambda is one of the most hardcore computer programming books out there. Starting with the fundamentals, it describes the most advanced features of the most advanced language: COMMON LISP. The point of this book is to expose you to ideas that you might otherwise never be exposed to.”

So you say that programming language choice does not matter ...

One popular interview question that never dies : write some code to reverse a singly linked-list.

Now understanding the problem for interviewees is one thing but getting it right in an imperative language seems to be quite a feat based on my experience as an interviewer. Most take 15-20 minutes to get this completely correct and sometimes even longer.

Here’s a quick solution that took me 10 minutes (in C) :

Convex Hull with Aki-Toussaint heuristics

;; Calculates the convex hull of a set of points using the Graham scan
;; algorithm.
(ns i27.geom.convex-hull
  (:use [i27.geom.misc :only (angle cross-product)]))
(defn presort-points [pts]
  "Presorts the cartesian points in descending order by angle.
   The point with lowest y value is last in the vector."
   (let [pts (distinct pts)] ;; must be distinct or else errors ...
    (letfn [(find-start [[x1 y1 :as pt1] [x2 y2 :as pt2]]
                (cond (< y1 y2) pt1
                  (= y1 y2) (if (< x1 x2) pt1 pt2)
                  true pt2))]
           (let [pt (reduce find-start pts)
             npts (remove (fn [[x y :as cpt]]
                      (and (= (first pt) x) (= (last pt) y))) pts)]
          (conj (apply vector
                   (sort (fn [pt1 pt2]
                     (> (angle pt pt1) (angle pt pt2))) npts))
            pt)))))
(defn convex-hull
  "Calculates the convex hull given a set of points in the cartesian plane.
   Uses the Graham scan algorithm. Performance is O(n lg n) time."
  [pts]
  (when (>= (count pts) 3)
    (let [start (apply vector
                       (reverse (subvec pts (- (count pts) 3) (count pts))))
          other (reverse (subvec pts 0 (- (count pts) 3)))]
      (letfn [(popstack [stk pt]
                        (if (not (> (cross-product
                                     (last (pop stk)) (last stk) pt) 0))
                          stk (recur (pop stk) pt)))
              (scan [res pt]
                    (conj (popstack res pt) pt))]
        (reduce scan start other)))))
(defn elim-points
  "Prepare data with Aki-Toussaint heuristics before passing to convex hull function.
   Performance is O(n) time regardless of the convex hull algorithm used."
  [pts]
  (when (>= (count pts) 4)
    (letfn [(find-quad
             [[[x1 y1 :as pt1] [x3 y3 :as pt3]
               [x2 y2 :as pt2] [x4 y4 :as pt4] :as quad] [xc yc :as cpt]]
             [(if (> x1 xc) cpt pt1) (if (> y3 yc) cpt pt3)
              (if (< x2 xc) cpt pt2) (if (< y4 yc) cpt pt4)])]
      (let [poly (distinct (reduce find-quad (take 4 pts) pts))
            ;; generate the line segments that form the convex polygon
            lines (conj (reduce (fn [lines pt] (conj lines [(last (last lines)) pt]))
                                [[(first poly) (second poly)]] (rest (rest poly)))
                        [(last poly) (first poly)])
            ;; filter out all points that fall inside the convex polygon
            pts (filter
                 (fn [tpt]
                   (not (reduce (fn [b v] (and b (neg? v))) true
                                (map (fn [pt]
                                       (cross-product tpt (first pt) (last pt)))
                                     lines))))
                 pts)]
        pts))))

Timing without heuristics :

Bucket sort (Clojure)

(defn bucket-sort
  "Runs in O(n) time."
  [items]
  (let [len (count items)
        mx (apply max items)
        bucket-size (inc (int (/ mx len)))
        buckets (reduce (fn [v n] (conj v [])) []
                        (range (+ bucket-size (/ mx bucket-size))))]
    (letfn [(distrib-nums [v n]
                          (let [ind (int (/ n bucket-size))
                                bucket (nth v ind)]
                            (assoc! v ind (conj bucket n))))]
      (let [pre-buckets (persistent!
                         (reduce distrib-nums (transient buckets) items))]
        (apply concat (map (fn [bucket]
                             (when (> (count bucket) 0)
                               (insertion-sort bucket))) pre-buckets))))))

Runs slightly faster than Clojure’s built-in sort (at least on integers in the range 0 to 1E6) :

java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8) (6b18-1.8-0ubuntu1)
OpenJDK 64-Bit Server VM (build 14.0-b16, mixed mode)
(let [cnt 1e6
      rnums (map (fn [n] (int (rand cnt))) (range cnt))]
  ;; warmup
  (doseq [c (range 10)]
    (take 10 (bucket-sort rnums))
    (take 10 (sort rnums)))
  ;; run
  (println (time (take 10 (bucket-sort rnums))))
  (println (time (take 10 (sort rnums)))))
"Elapsed time: 676.618148 msecs"
(0 0 1 1 4 4 5 7 8 10)
"Elapsed time: 897.640471 msecs"
(0 0 1 1 4 4 5 7 8 10)

The code.

The Dangers of Computer Science Theory

Quotes from Don E. Knuth :


“If we make an unbiased examination of the accomplishments made by mathematicians to the real world of computer programming, we are forced to conclude that, so far, the theory has actually done more harm than good. There are numerous instances in which theoretical “advances” have actually stifled the development of computer programming, and in some cases they have even made it take several steps backward!”

A molecule viewer in Clojure

Here’s a molecule viewer using OpenGL in Clojure. Implemented so that I could compare this type of development with Common Lisp (and also with using OpenGL development in C). OpenGL with Clojure can be really fun using Zach Tellman’s Penumbra. Coming at OpenGL from a more functional angle (e.g. not mutating global vars etc.) can be a little different but not difficult for anyone who has done enough functional programming.

The code is here.

Happy π approximation day/night (in assembly) !

//   pi_x64.s - calculates Pi using the Leibniz formula.
//              Each iteration prints a closer approximation to 50 digits.
//              This is not an optimal implementation and it runs forever.
//
//  x86-64/SSE3 with for Linux, Intel, gnu assembler, gcc
//
//  assemble: as pi_x64.s -o pi_x64.o
//  link:     gcc -o pi_x64 pi_x64.o
//  run:      ./pi_x64
//  output: 3.14159264858204423376264458056539297103881835937500
//          3.14159265108366625440794450696557760238647460937500
//          3.14159265191852199450295302085578441619873046875000
//          3.14159265233600137889879988506436347961425781250000
//          .... and on forever ...
.section .data
        .align 16
denom:  .double  1.0, 3.0
numer:  .double  4.0, -4.0
add4:   .double  4.0, 4.0
zero:   .double  0.0, 0.0
msg:    .string  "%1.50fn"
.section .text
        .globl main
        .type main, @function
        .align 64
main:
        pushq   %rbp
        movq    %rsp, %rbp
        movdqa  (numer), %xmm2
        movdqa  (denom), %xmm6
        movdqa  (add4), %xmm3
        movdqa  %xmm2, %xmm4
        movdqa  (zero), %xmm5
        movq    $100000000, %r12
loop:
        divpd  %xmm6, %xmm2
        addpd  %xmm2, %xmm5
        movdqa %xmm4, %xmm2
        addpd  %xmm3, %xmm6
        subq $1, %r12
        jnz loop
        movq   $100000000, %r12
        movdqa %xmm5, %xmm0
        movdqa %xmm6, %xmm1
        haddpd %xmm0, %xmm0
        movq  $1, %rax
        movq $msg, %rdi
        call printf
        movdqa (add4), %xmm3
        jmp loop
        movq $0, %rax
        popq %rbp
        ret

Do you really know Lisp ?

DISCLAIMER :

THIS IS A LANGUAGE RANT. DO NOT READ IF YOUR BPF* IS LESS THAN 0.37.

SIDE EFFECTS MAY INCLUDE SEVERE CONFUSION, UNJUSTIFIED ANGER, GASSY DISCHARGE,

INCOMPREHENSIBLE DIALOG, ERRATIC DEGRADATION OF CHARACTER AND POSSIBLY A

COMPLETE EMOTIONAL MELTDOWN.

Performance is one important aspect that people might want in a language. One language that continually surprises me in this regard is Haskell. Seriously, it’s simply amazing. But performance is only one important consideration when using a language. Abstraction is another.

Palindromes (Clojure)

**

  • Update 2009-12-27 * Using lists instead of vectors brings the Clojure version down from around 20x to 10X slower than the CL version. One reader correctly stated that when doing performance comparisons between languages and implementations you want the code and data structures to be as identical as possible.

**

“A palindrome is a word, phrase, number or other sequence of units that can be read the same way in either direction (the adjustment of punctuation and spaces between words is generally permitted.”

Winter 2009 reading

Sonoluminescence: A Galaxy of Nanostars Created in a Beaker (NASA)

The Idea Factory – Learning to Think at MIT, Pepper White :

“This is a personal story of the educational process at one of the world’s great technological universities. Pepper White entered MIT in 1981 and received his master’s degree in mechanical engineering in 1984. His account of his experiences, written in diary form, offers insight into graduate school life in general—including the loneliness and even desperation that can result from the intense pressure to succeed—and the purposes of engineering education in particular. The first professor White met at MIT told him that it did not really matter what he learned there, but that MIT would teach him how to think. This, then, is the story of how one student learned how to think.”

The Half-Life of Knowledge

Even a superficial study of learning theory can have great value :

The following article, “Connectivism: A Learning Theory for the Digital Age” is a great example.

High-lights include :

*Some significant trends in learning:

  • Many learners will move into a variety of different, possibly unrelated fields over the course of their lifetime.

  • Informal learning is a significant aspect of our learning experience. Formal education no longer comprises the majority of our learning. Learning now occurs in a variety of ways – through communities of practice, personal networks, and through completion of work-related tasks.

Clojure Quine

A Quine is a program that produces its complete source code as its only output.

Because Clojure is a Lisp, it is especially well suited to writing Quines. This is a quine implemented in Clojure.

((fn [x] (list x (list (quote quote) x))) (quote (fn [x] (list x (list (quote quote) x)))))

M.C. Escher – Drawing Hands – 1948

Play Pong!

A few updates and bug fixes from the

first version.

You can now play it here.

ACHTUNG ! : This requires unrestricted perms so you should probably just grab the code and compile it yourself.

Pong! (in Clojure)

  • UPDATED : 2009-09-17 * – rewritten in a functional style that is more idiomatic of Clojure.

A nostalgic attempt to try and learn some GUI programming in Clojure. Inspired by Pong in Haskell.

Play online here.

The computer seems unbeatable(but it’s not thanks to a bug as things get faster).

Have fun !

< 200 lines of code :

;;;;
;;;; Pong!
;;;;
;;;; Justin Grant
;;;; 2009/09/12
(ns i27.games.pong
  (:import (java.awt Color Toolkit Font GraphicsEnvironment Graphics2D)
           (java.awt.image BufferStrategy)
           (java.awt.event ActionListener MouseMotionListener KeyListener
                           MouseEvent KeyEvent)
           (javax.swing JFrame Timer)))
(defstruct ball :h :w :x :y :sx :sy)
(defn new-ball [& [h w x y sx sy]] (atom (struct ball h w x y sx sy)))
(defn set-ball-size [b h w] (swap! b assoc :h h :w w))
(defn set-ball-speed [b sx sy] (swap! b assoc :sx sx :sy sy))
(defn set-ball-position [b x y] (swap! b assoc :x x :y y))
(defstruct paddle :h :w :x :y)
(defn new-paddle [& [h w x y]] (atom (struct paddle h w x y)))
(defn set-paddle-size [p h w] (swap! p assoc :h h :w w))
(defn set-paddle-position [p x y] (swap! p assoc :x x :y y))
(defstruct game :h :w :timer :score :started :my)
(defn new-game [& [h w timer score started my]]
  (atom (struct game h w timer score started my)))
(defn set-game-size [g h w] (swap! g assoc :h h :w w))
(defn set-game-timer [g t] (swap! g assoc :timer t))
(defn set-game-score [g s] (swap! g assoc :score s))
(defn set-game-mouse-y [g my] (swap! g assoc :my my))
(defn stop-game [g]
  (swap! g assoc :started false) (let [#^Timer t (@g :timer)] (.stop t)))
(defn start-game [g]
  (swap! g assoc :started true) (let [#^Timer t (@g :timer)] (.start t)))
(defn reset-game [g b p c]
  (set-ball-size b (* (@g :h) 0.0335) (* (@g :h) 0.0335))
  (set-ball-position b
                     (- (/ (@g :w) 2) (/ (@b :w) 2))
                     (- (/ (@g :h) 2) (/ (@b :h) 2)))
  (set-ball-speed b 15 15)
  (set-paddle-size p (* (@b :h) 5) (@b :w))
  (set-paddle-position p 35 (- (/ (@g :h) 2) (/ (@p :h) 2)))
  (set-paddle-size c (@p :h) (@p :w))
  (set-paddle-position c (- (@g :w) (@p :x) (@p :w)) (@p :y))
  (set-game-score g 0))
(defn pong-frame [g b p c f1 f2]
  (proxy [JFrame ActionListener MouseMotionListener KeyListener] []
    (paint [grf]
           (let [#^JFrame me this
                 #^BufferStrategy bs (.getBufferStrategy me)
                 #^Graphics2D gr (if (not= nil bs) (. bs getDrawGraphics) nil)]
             (if (not= nil gr)
               (do
                 (.setColor gr Color/BLACK)
                 (.fillRect gr 0 0 (@g :w) (@g :h))
                 (.setColor gr Color/WHITE)
                 (.setFont gr f1)
                 (.drawString gr (str "SCORE " (@g :score)) 20 20)
                 (.fillRect gr (@p :x) (@p :y) (@p :w) (@p :h))
                 (.fillRect gr (@c :x) (@c :y) (@c :w) (@c :h))
                 (if (@g :started)
                   (.fillRect gr (@b :x) (@b :y) (@b :w) (@b :h))
                   (do
                     (.setFont gr f2)
                     (.drawString gr "PONG!"
                                  (- (/ (@g :w) 2) 46) (- (/ (@g :h) 2) 16))
                     (.setFont gr f1)
                     (.drawString gr "PRESS 'S' TO START, 'Q' TO QUIT"
                                  (- (/ (@g :w) 2) 200) (+ (/ (@g :h) 2) 30))))
                 (. gr dispose)
                 (. bs show)))))
    (mouseMoved [#^MouseEvent e]
                (set-game-mouse-y g (.getY e))
                (if (> (+ (@g :my) (/ (@p :h) 2)) (@g :h))
                  (set-game-mouse-y g (- (@g :h) (/ (@p :h) 2))))
                (if (< (@g :my) (/ (@p :h) 2))
                  (set-game-mouse-y g (/ (@p :h) 2)))
                (set-paddle-position p (@p :x) (- (@g :my) (/ (@p :h) 2)))
                (let [#^JFrame me this] (.repaint me)))
    (mouseDragged [e])
    (keyPressed [#^KeyEvent e]
                (when (and (not (@g :started)) (= (. e getKeyChar) s))
                  (reset-game g b p c) (start-game g))
                (when (= (. e getKeyChar) q) (System/exit 0)))
    (keyReleased [e])
    (keyTyped [e])
    (actionPerformed [e]
                     ;; update ball position
                     (set-ball-position
                      b (+ (@b :x) (@b :sx)) (+ (@b :y) (@b :sy)))
                     ;; update ball y direction
                     (when (or (= (+ (@b :y) (@b :h)) (@g :h)))
                       (set-ball-speed b (@b :sx) (* -1 (@b :sy))))
                     ;; check if player returns ball
                     (when (and (= (+ (@b :y) (@b :h)) (@p :y))
                                ( (@b :x) (@p :x)))
                       (set-ball-speed b (* -1 (@b :sx)) (@b :sy))
                       (set-game-score g (inc (@g :score)))
                       (set-ball-speed b (+ 1 (@b :sx)) (@b :sy))) ; game gets faster
                     ;; check when computer returns ball
                     (when (and (>= (+ (@b :x) (@b :w)) (@c :x))
                                (>= (+ (@b :y) (@b :h)) (@c :y))
                                ( (+ (@c :y) (/ (@p :h) 2)) (/ (@g :h) 2))
                           (set-paddle-position
                            c (@c :x) (- (@c :y) (* -1 (@b :sx))))
                           (set-paddle-position
                            c (@c :x) (+ (@c :y) (* -1 (@b :sx))))))
                       (if ( (+ (@c :y) (@p :h)) (@g :h))
                       (set-paddle-position c (@c :x) (- (@g :h) (@p :h))))
                     ;; check game over
                     (when (or (< (+ (@b :x) (@b :w)) 0)
                               (> (+ (@b :x) (@b :w)) (@g :w)))
                       (set-paddle-position p (@p :x)
                                            (- (/ (@g :h) 2) (/ (@p :h) 2)))
                       (stop-game g))
                     (let [#^JFrame me this]
                       (.repaint me)))))
(defn -main []
  (let [tk (. Toolkit getDefaultToolkit)
        ge (GraphicsEnvironment/getLocalGraphicsEnvironment)
        gd (. ge getDefaultScreenDevice)
        thegame (new-game (.. tk getScreenSize height)
                          (.. tk getScreenSize width))
        theball (new-ball)
        theplayer (new-paddle)
        thecomputer (new-paddle)
        #^JFrame screen (pong-frame
                         thegame theball theplayer thecomputer
                         (Font. "Courier New" Font/BOLD 24)
                         (Font. "Courier New" Font/BOLD 44))]
    (set-game-timer thegame (Timer. 20 screen))
    (if (not (. screen isDisplayable)) (. screen setUndecorated true))
    (.setVisible screen true)
    (. (.getContentPane screen) setBackground Color/BLACK)
    (. (.getContentPane screen) setIgnoreRepaint true)
    (doto screen
      (.setResizable false)
      (.setBackground Color/BLACK) (.setIgnoreRepaint true)
      (.addMouseMotionListener screen) (.addKeyListener screen))
    (. gd setFullScreenWindow screen)
    (. screen createBufferStrategy 2)
    (reset-game thegame theball theplayer thecomputer)))
(-main)

Calculating π in Clojure (Salamin-Brent)

Took a shot at implementing a PI digit generator in Clojure using a ‘fast’ algorithm.

It seemed like a decent enough excercise to try and understand something about performance in Clojure.

MacBook Pro – Intel Core 2 Duo 2.26 GHz – 4GB RAM

Java(TM) SE Runtime Environment (build 1.6.0_15-b03-219)

Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02-90, mixed mode)

Clojure 1.1.0-alpha-SNAPSHOT (Aug 20 2009) git commit f1f5ad40984d46bdc314090552b76471ee2b8d01

Clojure matches the performance of Java in this example.

Another slice of π ?

The previous Common Lisp and Haskell functions to generate the digits of PI where only accurate between 10000 and 20000 digits. The algorithm uses an approximation where we discard a certain number of ‘guard’ digits to get an accurate result. Some background regarding how the number of guard digits is calculated : There is ‘wobble’ in the number of contaminated digits depending on the number of input digits. When only the order of magnitude of rounding error is of interest, ulps(units in the last place) and ε (machine precision) may be used interchangeably, since they differ by at most a factor of β (the ‘wobble’ in the number of contaminated digits). For example, when a floating-point number is in error by n ulps, that means that the number of contaminated digits is about logβn. [1] [2]

Generating π in Haskell

Haskell beats CL quite comfortably using the same algorithm :

module Main( main ) where
import System( getArgs )
arccot :: Integer -> Integer -> Integer
arccot x unity =
    arccot' x unity 0 start 1 1
      where start = unity `div` x
            arccot' x unity sum xpower n sign | xpower `div` n == 0 = sum
                                              | otherwise           =
                arccot' x unity (sum + sign*term) (xpower `div` (x*x)) (n+2) (-sign)
                  where term = xpower `div` n
machin_pi :: Integer -> Integer
machin_pi digits =
    pi' `div` (10 ^ 10)
      where unity = 10 ^ (digits+10)
            pi' = 4 * (4 * arccot 5 unity - arccot 239 unity)
main :: IO ()
main = do
    args <- getArgs
    putStrLn (show (machin_pi (read (head args) :: Integer)))

The first 10000 digits.

> time ./machin_pi 10000
31415926535897932384626433832795028841971693993751058209749445923078164062862089 ...
real    0m0.381s
user    0m0.290s
sys     0m0.061s
Saintly Man? - That Mitchell & Webb Look - BBC Two

Generating π in CL (faster)

Thanks to metacircular for pointing out that (floor (/ x y)) can be written as (floor x y) while avoiding

the intermediate rational.

(defun machin-pi (digits)
  "Calculates PI digits using fixed point arithmetic and Machin's formula with double recursion"
  (labels
      ((arccot-minus (xsq n xpower)
         (let ((term (floor xpower n)))
           (if (= term 0)
               0
               (- (arccot-plus xsq (+ n 2) (floor xpower xsq))
                  term))))
       (arccot-plus (xsq n xpower)
         (let ((term (floor (/ xpower n))))
           (if (= term 0)
               0
               (+ (arccot-minus xsq (+ n 2) (floor xpower xsq))
                  term))))
       (arccot (x unity)
         (let ((xpower (floor (/ unity x))))
           (arccot-plus (* x x) 1 xpower))))
    (let* ((unity (expt 10 (+ digits 10)))
           (thispi (* 4 (- (* 4 (arccot 5 unity)) (arccot 239 unity)))))
      (floor thispi (expt 10 10)))))

The first 10000 digits again.

* (time (machin-pi 10000))
Evaluation took:
  0.662 seconds of real time
  0.634038 seconds of total run time (0.495454 user, 0.138584 system)
  [ Run times consist of 0.233 seconds GC time, and 0.402 seconds non-GC time. ]
  95.77% CPU
  1,491,387,858 processor cycles
  109,530,592 bytes consed
31415926535897932384626433832795028841971693993751058209749445923078164062862089 ...

Algorithmic optimizations would take us much further. For example the Gauss–Legendre or Salamin–Brent formula.

Generating π in CL

Update 2009-07-23 : Faster version in CL and a Haskell version.

——————————————————————————–

A trivial approximation using the Leibniz formula.

(defun leibniz-pi()
  (labels ((local-pi(sum n)
             (if (< n (expt 10 6))
                 (local-pi
                  (+ sum (/ (expt -1 n) (+ (* 2 n) 1)))
                  (+ n 1))
                 sum)))
    (* 4 (local-pi 0f0 0f0))))

And here’s a longer version(but faster and more precise) using Machin’s formula with fixed point arithmetic to x digits.

(defun machin-pi (digits)
  "Calculates PI digits using fixed point arithmetic and Machin's formula with double recursion"
  (labels
      ((arccot-minus (xsq n xpower)
         (let ((term (floor (/ xpower n))))
           (if (= term 0)
               0
               (- (arccot-plus xsq (+ n 2) (floor (/ xpower xsq)))
                  term))))
       (arccot-plus (xsq n xpower)
         (let ((term (floor (/ xpower n))))
           (if (= term 0)
               0
               (+ (arccot-minus xsq (+ n 2) (floor (/ xpower xsq)))
                  term))))
       (arccot (x unity)
         (let ((xpower (floor (/ unity x))))
           (arccot-plus (* x x) 1 xpower))))
    (let* ((unity (expt 10 (+ digits 10)))
           (thispi (* 4 (- (* 4 (arccot 5 unity)) (arccot 239 unity)))))
      (floor (/ thispi (expt 10 10))))))

The first 10000 digits.

A fast MAPCONCAT implementation in Common Lisp

Here’s an implementation of Emacs Lisp’s MAPCONCAT function for Common Lisp.

(defun mapconcat (fun list sep)
   (when list
      (let ((~sep (with-output-to-string (*standard-output*)
                     (map nil (lambda (ch) (princ (if (char= #~ ch) "~~" ch))) sep))))
       (format nil (format nil "~~A~~{~A~~A~~}" ~sep)
               (funcall fun (first list))
               (mapcar fun (rest list))))))

timed :

* (time (mapconcat 'identity *mylist* "-"))
 Evaluation took:
   2.805 seconds of real time
   2.746358 seconds of total run time (2.736834 user, 0.009524 system)
   [ Run times consist of 0.004 seconds GC time, and 2.743 seconds
     non-GC time. ]
   97.90% CPU
   6,324,642,149 processor cycles
   17,734,520 bytes consed
 "0-1-2-3-4-5-6-7-8-9-10- ... "

And here’s an optimized version.

It's good to be wrong about Lisp performance

The last article ended with a challenge hoping that someone would

come up with an improved version of the boggle solver that beats my version.

Well someone did, they also proved that with this particular algorithm

the Lisp version can match C within about 20%. Very good !

Here are the new graphs (note that the first is no longer on a logarithmic scale).

The patches have been merged into the

boggle repo.

IWTB (in Lisp performance) - a followup

The previous article had some serious traffic yesterday and today.

Due to abuse of the moderation system on some sites I’ve been forced to present my response here separately.

To the SBCL contributor : Relax, SBCL is still a great Lisp compiler. It always has been and I’m sure it always will be. Your work on the compiler is appreciated. It’s unfortunate that you seem to fit the pontificating arm-chair theoretician stereo-type. You do have a few valid points to share in spite of your mostly incorrect presumptions regarding the Lisp code. The single worthwhile and correct contribution that you made to the discussion was your suggestion on type declarations in the critical path of the code. Thanks for that, you were one of only two people that has actually addressed the performance of the code so far. I posed a challenge to you because of your claims of being able to easily bring the code within under 3x the slowness of the C version. Your dismissive refusal to substantiate your claims with any real evidence speaks volumes to a wide ranging audience now.

I want to believe (in Lisp performance)

* Update 2009-05-06 : The challenge has been met ! See the new graphs of performance. *

myths and legends

The myths and legends precede the language. Lisp.

(The same holds true for its dialects and derivatives.)

Its ‘bizarre’ syntax, its alleged ability to stand up to low level language performance, the unique and powerful abstractions awarded the programmer who even dares to attempt its almost vertical cliff face of learning. Or so it seemed back then. With its more recent popularity there’s been much hype surrounding its capabilities and especially so in contrast to other languages.

Integral Calculus in Lambda Calculus (Lisp)

A Lisp version of the code from this article –>

http://iam.elbenshira.com/archives/151_integral-calculus-in-haskell/


For those that are unhappy about this not being a Symbolic Integration example then please read Norvig’s “Paradigms of Artificial Intelligence Programming – Case Studies in Common Lisp”, Chapter 8 – Symbolic Mathematics : A Simplification Program, 8.6 – Integration, page 252.

http://norvig.com/paip.html


(defparameter *small-dx* 0.0001)
(defun integrate(f a b)
  "integrate a function f from a to b"
    (defun integrate-gen(f x b dx sum)
      "the generalized inner function for tail-recursion.
       integrate a function f from x to b"
      (if (> x b)
          sum
          (integrate-gen f (+ x dx) b dx (+ sum (* (funcall f x) dx)))))
    (integrate-gen f a b *small-dx* 0))
(let
    ((f1 (lambda (x) 1))
     (f2 (lambda (x) (expt x 2)))
     (f3 (lambda (x) (* x (exp (expt x 2))))))
  (print (integrate f1 0 5))
  (print (integrate f3 0 1)))

Live Lisp coding as art.

Andrew Sorenson is doing some beautiful live “Lisp coding as art” with synthesized sound and OpenGL.

Give the video some time to start up or skip ahead (at least 3 minutes).

Problems with optimizing Common Lisp code

Before I go any further : let me state upfront that knowing Lisp has changed me as a programmer for the best. It’s been an invaluable experience that I’ve carried into every corner of my career and every other language that I’ve coded with.

Now that we have that out of the way let’s move on…

There are a number of problems with Common Lisp that go unmentioned in the community. The fact that a prominent member of the CL community has recently highlighted these(at ILC 2009 no less) could be viewed as a break-through for the language in itself. The show-stoppers in my opinion from personal experience and which I’ve faced in trying to write code that performs acceptably in time and space :

A language analogy for the decade

Ron Garret puts it’s perfectly :

“Whatever problems I may have, an unwillingness to learn new things is not one of them. I love to learn new things. That’s one of the reasons I hate Java, because learning Java didn’t teach me anything except how truly brain-damaged a language can be. (I’ve never learned Perl, but I’ve never learned how to run the deep fryer at a McDonalds either. I like learning new things, but life is short and there are some things I’m content not to know.)”

Books for Spring 2009

Brave New World – Aldous Huxley : Re-reading but not from any paradise-engineering paranoia perspective. Simply insightful, focused and a great style. First covered this in high school decades ago. It’s ironic and deviously cool that this was actually course mandated at my high school ! (Have yet to finish Island.)

Pugetopolis – Knute Berger : The Seattle analog of Palahniuk’s A Walk in Portland, Oregon.

Useful because apparently Seattle is one of America’s most difficult cities to grok.

Some 2007 Reading / Listening

Reading

**Robert Cialdini’s “Influence” – **

Plenty of social psychology observations that should be common sense if you’re paying attention to the world around you. Read it on recommendation thanks to Scott Adams.

**Neil Gaiman’s “American Gods” – **

Yea yea, it’s nothing new but got through it last year and realize why his books morph fairly quickly into Hollywood scripts. Not much else to say about it.

Firefox 3.0 BETA 2 on FreeBSD 6

UPDATE (2008-01-06) : Here’s a 64-bit build for amd :

firefox-3.0b2-en-US.freebsd62-x86_64-static.tar.bz2

(md5 21bfa5c75d9b3df11f939a07a9bb94bc)


If anyone wants to test Firefox 3.0 BETA 2 on FreeBSD then then here’s a static build. (I’ve only tried it on 6.2 let me know if you have a different version)

firefox-3.0b2-en-US.freebsd62-i386-static.tar.gz

(md5 0a8035908790bfb2d0b1e14eeb8407c0)

I couldn’t find a 3.0b2 build for FreeBSD on the Mozilla site. Pretty normal though I’m guessing most FreeBSD folks just wait for newer versions to show up in Ports.

True Stories About the Future

A movie with a cast including Ray Kurzweil(as himself), Marvin Minsky, self-help guru Anthony Robbins, Alvin Toffler, Mitch Kapor, Bill Joy, Aubrey de Gray and more.

This is a joke right ? Wrong. It’s near, apparently some time in 2008.

Plot outline : “Computer avatar saves the world from self-replicating microscopic robots.”

On a similar singular note, James Cameron’s Avatar is another sci-fi flick coming soon in the slightly further off but still near future.

Commercial Software Development &amp; Scarcity

Zyzyxx Rd., Mojave Desert, California

*… the commercial software community has developed one particular response to resource limitation: a fevered, workaholic approach to software development—error prone, hectic, family-destroying, health-degrading, night-haunting. If you are undermanned by a factor of 2, add a second 8-hour workday per physical day. If you are operating under a schedule 50% too short, add in another 32 hours per week by working weekends. Then pray for luck or push back on features and quality.

Haskell vs. Lisp (tail-recursion)

Some Haskell fans seem impressed with better performance for a fibonacci function compared with similar implementations in Ruby and Python. They should be. I may be turning into a Haskell fan myself actually. Here’s why …

Read this and this before going on.

Impressive. Yea I thought so too until I implemented the same fib function in Lisp and ran it on SBCL.

Here it is…

(defun print-fib-trec-naive (start end)
  (format t "n=~D => ~D~%" start (fib-trec start))
  (if (< start end)
      (print-fib-trec-naive (+ start 1) end))))
(defun fib-trec-naive (n)
  "Naive tail-recursive Fibonacci number function"
  (if (or (= n 0) (= n 1))
      n
      (+ (fib-trec-naive (- n 1)) (fib-trec-naive (- n 2)))))

and here are comparable results for N=45.

Bottle that can filter viruses out of water

According to this telegraph article : “an Ipswich-based businessman invented a £190 bottle that makes foul-smelling water drinkable in seconds.”

That’s about US$380 over here. Each bottle can filter 4000 or 6000 liters without changing the filter.

Also the bottle can make fecal matter safe to drink because it filters anything longer than 15 nanometres. This means that bacteria which are smallest at 200 nanometres(filterable by conventional water filters) and even viruses which are usually smallest at 25 nanometers can be filtered.

Reverse superclass envy and bad mental pointers

I’ve ranted previously about Python and made promises of future posts about why Ruby is so much cooler. It really is and the topic of this article covers one of the common idioms used by most Ruby folks who may have taken a shot at their own domain specific language in Ruby. The following is one of the really useful idioms but apparently not a very well understood or well explained one for Ruby coders.

Recursive reduction

The previous post was pretty grumpy about Python/Django and I was going to write a follow-up about why Ruby is a better language (unfortunately not the platform’s performance just yet but that is soon to change with YARV).

For this post to appear more fair about Ruby/Python than the last let’s look at one reason where these don’t come close to Lisp. This is something mentioned less often(but still important) when comparing Lisp with other languages which usually focus on macros and s-exprs.

RIA/D

Thanks John for bringing this one up.

The Regressive Imagery Dictionary (RID) is a coding scheme for text analysis that is designed to measure ‘primordial’ and conceptual content. Primordial thought is the kind of free-form, associative thinking involved in fantasy and dreams. Like Freud’s id, I guess. Conceptual (or secondary) thought is logical, reality-based and focused on problem solving.

RID contains about 3,000 words grouped into categories that are themselves classified as primary, secondary, and emotional. A piece of text is classified by what percentage of its words fall into each category.

Memetic Malkovich

‘Being John Malkovich’ is a 1999 film written by Charlie Kaufman and directed by Spike Jonez.

The movie stars John Cusack, John Malkovich, Cameron Diaz, Catherine Keener, Charlie Sheen, Orson Bean and Mary K. Place.

  • warning – mini spoiler below *

    The film centers around Craig Schwarz(John Cusack) who finds a portal into John Malkovich’s subconscious. He exploits this to win the affection of Maxine(Catherine Keener) who he is in love with but has no interest in Craig.

  • Strongly typed software disasters

    the.codist seems to have these down accurately so far.

    The Train Wreck

    ‘A train wreck is a project where everyone assumes things are going well, progress is being made, and it appears that everything will turn out well. In reality, the train is barreling down the tracks at good speed until it hits the bridge that is out and then crashes spectacularly into the valley. No one is actually driving the train and all anyone sees is out the side windows, so the illusion of progress is great.’

    There goes the neighborhood...

    …thanks to Google, Yahoo and Microsoft.

    “THE DALLES, Ore., June 8 — On the banks of the windswept Columbia River, Google is working on a secret weapon in its quest to dominate the next generation of Internet computing. But it is hard to keep a secret when it is a computing center as big as two football fields, with twin cooling plants protruding four stories into the sky.”

    NY Times article

    From the archives...

    Artificial Intelligence

    An early look at artificial Intelligence. Guests includes Edward Feigenbaum of Stanford University, Nils Nilsson of the AI Center at SRI International, Tom Kehler of Intellegenetics, Herb Lechner of SRI, and John McCarthy of Stanford. Featured demonstrations include Inferential Knowledge Engineering and the programming language LISP. Originally broadcast in 1984.

    AND

    Daniel G Bobrow: Common LISP Object Standard (1987)

    Lisp and game development

    Regarding the role of Lisp and game development (specifically on the PS2), Andy Gavin has this to say…

    “Lisp was just the best solution for this job,” comments Gavin. “With leading edge game systems like ours, you have to deal with complicated behaviors and real-time action. Languages like C are very poor with temporal constructs. C is just very awkward for a project like this. Lisp, on the other hand, is ideal.”

    Paul Graham on the traditional office

    *“To me the most demoralizing aspect of the traditional office is that you’re supposed to be there at certain times. There are usually a few people in a company who really have to, but the reason most employees work fixed hours is that the company can’t measure their productivity.

    The basic idea behind office hours is that if you can’t make people work, you can at least prevent them from having fun. If employees have to be in the building a certain number of hours a day, and are forbidden to do non-work things while there, then they must be working. In theory. In practice they spend a lot of their time in a no-man’s land, where they’re neither working nor having fun.