I just learned something about how git handles multi-line commit messages. If a commit message has a blank second line, git will treat the first line as the “subject” and the 3rd and following lines as the “body”. This will allow some nice things to be done with the git log command.

For example, the following command:

git log --pretty=format:"%ai %an: %s%n%n%b%n"

Will produce output such as this:

2010-08-30 13:10:51 -0400 Brian Adkins: This is my second commit for this example.

And this is the body for the second commit.
Second line of the body.

2010-08-30 13:07:23 -0400 Brian Adkins: This text will be treated as the subject.

This text will be treated as the body. The subject should be
a short summary of the commit since you may want to show just
the subject on some git log invocations.

If you just want to see the “subject”, use:

git log --pretty=format:"%ai %an: %s%n"

Which will display as follows:

2010-08-30 13:10:51 -0400 Brian Adkins: This is my second commit for this example.

2010-08-30 13:07:23 -0400 Brian Adkins: This text will be treated as the subject.

See “git log –help” for various formatting specifications.

Thanks to Nathaniel Talbott for the chat message that prompted me to look into this.

Tags:

Wow – pretty amazing! HT Michael Hale via RT :)

Tags: ,

Thanks to a tip from David Joyner, I discovered that the current version of Emacs will easily build an Emacs.app application for Mac OSX i.e. I no longer need to install the CarbonEmacs application. I’m thankful to Seiji Zenitani for creating CarbonEmacs, but I’m glad to be able to build the app directly from the latest Emacs source code.

Here’s what I did:

Get the source code and build it

git clone git://git.savannah.gnu.org/emacs.git
cd emacs
./configure --with-ns
make install

Copy Emacs.app to Applications

Drag nextstep/Emacs.app to Applications

Modify Emacs config files

I had several configuration items I needed to adjust.

carbon-emacs-package-add-to-path no longer exists

I used the above command to set the path to allow running programs via shell-command as follows:

(carbon-emacs-package-add-to-path "/Users/badkins/sync/bin")
(defun my-fun ()
  (interactive)
  (shell-command "my_ruby_script.rb"))

I found a comment by Alex Payne on Ola Bini’s blog that provided an equivalent for Emacs.app:

(setq path "/Users/badkins/sync/bin")
(setenv "PATH" path)

Use command for meta instead of alt/option

The newly built Emacs.app used the alt/option key for meta instead of the command key that I was used to with CarbonEmacs. The following (found on Hacker News) took care of that:

(setq ns-command-modifier 'meta)

Prior to the above, I had tried the following. It worked, but was more verbose:

(setq mac-option-key-is-meta nil)
(setq mac-command-key-is-meta t)
(setq mac-command-modifier 'meta)
(setq mac-option-modifier nil)

Allow use of command-h to minimize Emacs

After the above fix for the command key, I could no longer minimize Emacs via command-h because Emacs mapped M-h to a command. The following key binding allowed using M-h to minimize again:

(global-set-key (kbd "M-h") 'ns-do-hide-emacs)

Customize exec-path variable

I was having difficulty using the built-in vc git support. It turns out that Emacs wasn’t able to find the git command because it wasn’t in the exec-path. I customized the exec-path variable to include /opt/local/bin where git resides as follows (it’s within the custom-set-variables invocation):

 '(exec-path (quote ("/usr/bin" "/bin" "/usr/sbin" "/sbin" "/Applications/Emacs.app/Contents/MacOS/bin" "/opt/local/bin")))

Emacs is Awesome

That was all it took to get the latest Emacs up and running equivalently to CarbonEmacs for me. I’m more pleased with Emacs today than when I started using it in earnest in 2008. I’m continually learning new things to be more productive. There are just so many things that it does very well, and it’s so extensible and introspective.

Tags: ,

Found this Guy Kawasaki video on Duff O’Melia’s blog and enjoyed it.

Tags:

I compiled some programming language popularity statistics in April and mentioned I’d update the results in 6 months, so here they are:

I made a number of Google searches of the forms below and averaged the results:

"implemented in <language>"
"written in <language>"

Language # Results
Apr 09
# Results
Oct 09
Position
Delta
C 1,905,500 16,975,000 0
C++ 699,000 6,270,000 +1
Java 850,000 5,118,000 -1
PHP 680,000 5,083,500 0
Lisp Family1 176,507 3,489,650 +3
Python 396,000 3,407,000 -1
Perl 365,500 3,132,500 -1
C# 349,700 2,125,000 -1
Scheme 86,450 2,100,000 +2
FORTRAN 1,621,000 N/A
JavaScript 102,700 1,163,000 -1
ML Family2 29,062 1,003,800 +3
(S)ML3 5,173 590,700 +12
Common Lisp 20,600 554,500 +5
Lisp 61,900 486,500 -2
Prolog 17,750 390,500 +4
Tcl 44,800 382,000 -3
OCaml 22,000 343,500 0
Arc 6,775 286,500 +4
Haskell 22,550 280,500 -4
COBOL 247,300 N/A
Ruby 99,650 227,000 -10
Io 1,760 198,500 +6
Smalltalk 9,105 187,500 -1
Erlang 22,285 161,700 -7
Forth 6,465 146,450 -1
Lua 13,065 131,800 -5
Caml 1,889 69,600 0
Scala 3,570 66,250 -2
Clojure 782 62,200 0

1 combines Lisp, Scheme, Common Lisp, Arc & Clojure
2 combines OCaml, (S)ML, Caml
3 summed separate searches for sml and ml

Tags: , , , , , , , , , , , , , , , , , , , ,

Some random notes:

  • 650 KLOC plus 150 KLOC of open source code
  • 100 people on the team, 70 programmers
  • SBCL for the QPX product
  • Clozure CL for the reservations product
  • Availability requirement: four 9’s => less than 53 minutes downtime per year
  • Latency agreement

    • 90% of requests w/in 300 ms
    • 5% of requests w/in 600 ms
    • 5% of requests w/in 1,200 ms
  • Java presentation layer, Common Lisp stateless business layer, Oracle data layer
  • Daniel is very positive about Clojure
  • Some links from the talk:



Tags:

As I explain in 2009 Programming Language Plan, I’ve been in the process of evaluating programming languages to determine their suitability for use in my work. I’ve been proceeding on two fronts – statically typed functional programming languages and the venerated Lisp family.

Haskell The Hope Of The Statically Typed Family

After many hours of research and a brief dive into Standard ML, I’ve selected Haskell as the best candidate for me to evaluate statically typed functional programming languages. At this point, I’m subjectively biased against statically typed functional programming languages because of the enjoyment and productivity I’ve found in Ruby & Lisp, but my only experience with statically typed languages (C, C++, Java) has not been representative of good statically typed languages, so I’m reluctant to form a strong opinion of static typing before I’ve become proficient in a good statically typed language.

There are, of course, a number of respected statically typed functional programming languages, but I think Haskell provides me with the best opportunity to make a personal assessment regarding the benefits of static typing for my particular situation, and I think someone would be hard pressed to convince me that it’s a poor choice objectively.

There Can Be Only One

After working halfway through Programming in Standard ML by Robert Harper, I realized that I enjoy the language and it seems simpler & cleaner than Haskell, but I also realized that I only have time to become truly proficient in one statically typed functional programming language in the near future. I feel that a reasonable level of proficiency is required to evaluate a language well. I have seen many examples of someone, with only a little knowledge of a programming language, making an unfounded criticism of a programming language, or a particular feature, only to be corrected with an accurate, elegant and convincing counter argument by someone who is experienced with the language.

A quick survey of a language won’t be enough for me to make a decision on some key points such as static vs. dynamic, nonstrict vs. strict, pure vs. impure, etc. as well as important peripheral issues such as existing libraries, tools, etc. – it’s going to require understanding some of the subtleties of the language and writing enough code to get a feel for the language, so I felt I needed to limit my choice to one statically typed FPL.

Static vs. Dynamic

Clearly both static and dynamic typing work well for large numbers of people. One of my goals is simply to answer the static vs. dynamic question for myself given my preferences and the type of software I want to develop. I’d previously decided to learn both Standard ML and Haskell, so my reasons below for choosing Haskell are primarily with respect to comparing the two languages:

Haskell Is Pure And Lazy

I’m already familiar with impure, or multi-paradigm, programming languages that offer some functional features but allow imperative programming, so being forced to program in a purely functional manner and abandon my comfort zone of imperative patterns is an advantage for me. I have no experience with lazy languages, so Haskell offers an opportunity to gain more experience with laziness :).

In some respects, Haskell is more different than Lisp compared to other statically typed functional programming languages, so it’s a good point of comparison. It may end up being the ultimate death match :)

  • Static vs. Dynamic
  • Nonstrict vs. Strict
  • Rich/Complex Syntax vs. Simpler Syntax
  • Pure vs. Impure/Multi-paradigm

Active Community

Haskell has a very active community. Although I’m skeptical about whether a statically typed functional programming language will be suitable for the type of work I want to do with it, it makes sense to choose one that has a reasonable shot, and I don’t personally feel that Standard ML does – it was mainly to be an introduction to functional programming and a stepping stone to another FPL.

Part of the reason I don’t feel that Standard ML has a reasonable shot is that it feels dated and somewhat abandoned. Functional programming languages are niche languages to begin with, but it seems that Haskell and OCaml both have fairly strong communities.

Cool Features

Although I think Haskell’s custom of continuing to add cutting edge research features into the language may have some disadvantages if not done well, i.e. making the language messier and complicated, for my primary purpose of evaluating the benefits of statically typed languages, I think having more advanced features is an advantage over Standard ML. If a language with such an active research community as Haskell fails to convince me of the benefits of static typing, then it may just not be for me.

Monads and type classes seem interesting, and Haskell provides an opportunity to learn them. Monads seem useful outside of Haskell, so the time spent learning about them can be leveraged. I already like list comprehensions, so it’s nice to have them available again.

Learning some of the advanced features of Haskell will be beneficial to me regardless of whether I continue programming in Haskell or decide to go with the Lisp family.

Textual Resources

Standard ML actually has a surprising number of good texts available, so I don’t think Haskell offers a big advantage here, but in my particular case, I already own two Haskell texts – Programming in Haskell by Graham Hutton and The Craft of Functional Programming by Simon Thompson. Also, Chris Okasaki’s Purely Functional Data Structures provides Haskell examples as does Richard Bird’s Introduction to Functional Programming using Haskell (2nd ed.). Lastly, I think Real World Haskell may be very helpful.

Haskell Crash Course

My goal now on the statically typed front is to become as proficient in Haskell as I can in a very short period of time. There seem to be plenty of resources available, but if you’re aware of any particularly helpful resources or tips, feel free to add a comment.

Tags:

Table of Contents

Chapter 6 – Case Analysis

Tuple types are homogeneous e.g. all values of type int*real are pairs containing an int and a real. Match failures occur at compile time. Types that have more than one form, such as int, are heterogeneous. Pattern matches fail at run time as a bind failure.

ML defines functions over heterogeneous types using clausal function expressions. For example:

fn pat1 => exp1
 | pat2 => exp2
 | ...
 | patn => expn

Each component pat => exp is called a clause, or a rule. The entire assembly of rules is a called a match. For example:

val recip : int -> int =
    fn 0 => 0 | n:int => 1 div n

The fun notation is generalized so we can be more concise:

fun recip 0 = 0
  | recip (n:int) = 1 div n

Case analysis on the values of a heterogeneous type is performed by application of a clausally-defined function. The notation:

case exp
  of pat1 => exp1
   | ...
   | patn => expn

is short for the application:

(fn pat1 => exp1
  | ...
  | patn => expn)
exp

Matches are subject to two forms of “sanity check” – exhaustiveness checking and redundancy checking.

Chapter 7 – Recursive Functions

For a function to be able to call itself, it needs a name. For example:

val rec factorial : int->int =
    fn 0 => 1 | n:int => n * factorial (n-1)

or using fun notation:

fun factorial 0 = 1
  | factorial (n:int) = n * factorial (n-1)

Iteration

If we define a helper function that accepts an accumulator we can reduce the storage needed:

fun helper (0,r:int) = r
  | helper (n:int,r:int) = helper (n-1,n*r)
fun factorial (n:int) = helper (n,1)

It’s better programming style to hide the helper function w/in a local declaration:

local
    fun helper (0,r:int) = r
      | helper (n:int,r:int) = helper (n-1,n*r)
in
    fun factorial (n:int) = helper (n,1)
end

Tail recursive functions are analogous to loops in imperative languages – they iterate the computation w/o needing auxiliary storage.

Mutual Recursion

Definitions which are mutually recursive can be joined together with the and keyword to indicate they are defined simultaneously by mutual recursion:

fun even 0 = true
  | even n = odd (n-1)
and odd 0 = false
  | odd n = even (n-1)

Chapter 8 – Type Inference and Polymorphism

Standard ML allows you to omit type information whenever it can be determined from context. Consider the following:

fn s:string => s ^ "\n"

There is no need to declare the type of s since it can be inferred from the context, so we may write:

fn s => s ^ "\n"

A type scheme is a type expression involving one or more type variables standing for an unknown, but arbitrary type expression. Type variables are written ‘a (pronounced alpha), ‘b (pronounced beta), etc. For example, the type scheme ‘a->’a has instances int->int, string->string, (int*int)->(int*int), and (’b->’b)->(’b->’b), etc. It does not have the type int->string.

We may bind an identity function to the variable I as follows:

val I : 'a->'a = fn x=>x

We may also write:

fun I(x:'a) : 'a = x

Standard ML eliminates the need to ascribe a type scheme to the variable:

val I = fn x=>x

or

fun I(x) = x

Chapter 9 – Programming with Lists

The values of type type list are the finite lists of values of type type:

1. nil is a value of type typ list.
2. if h is a value of type typ, and t is a value of type typ list,
   then h::t is a value of type typ list.
3. Nothing else is a value of type typ list.

The type expression typ list is a postfix notation for the application of the type constructor list to the type typ.

A value val of type typ list has the form:
val1 :: (val2 :: (… :: (valn :: nil) … ))

The :: operator is right-associative, so we may omit parentheses:
val1 :: val2 :: … :: valn :: nil

Or, we may use list notation:
[ val1, val2, ..., valn ]

Computing With Lists

Some examples:

fun length nil = 0
  | length (_::t) = 1 + length t

Note we do not give a name to the head of the list, instead we use a wildcard _

fun append (nil, l) = l
  | append (h::t, l) = h :: append (t, l)

The latter is built into Standard ML and is written using infix as: exp1 @ exp2

fun rev nil = nil
  | rev (h::t) = rev t @ [h]

The running time of the latter is O(n2). The following definition makes use of an accumulator and has a running time of O(n):

local
    fun helper (nil, a) = a
      | helper (h::t, a) = helper (t, h::a)
in
    fun rev' l = helper (l, nil)
end

Chapter 10 – Concrete Data Types

Non-Recursive Datatypes

Example of nullary i.e. zero argument, constructors:

datatype suit = Spades | Hearts | Diamonds | Clubs

It is conventional to capitalize the names of value constructors, but this is not required by the language.

Datatypes may be parameterized by a type:

datatype 'a option = NONE | SOME of 'a

The values are NONE or Some val, where val is a value of type typ. The option type constructor is pre-defined in Standard ML.

Option types can also be used in aggregate data structures:

type entry = { name:string, spouse string option }

An entry for an unmarried person would have a spouse field with a value of NONE.

Recursive Datatypes

datatype 'a tree =
  Empty |
  Node of 'a tree * 'a * 'a tree

1. The empty tree Empty is a binary tree.
2. If tree_1 and tree_2 are binary trees, and val is a value of type type, then Node (tree_1, val, tree_2) is a binary tree.
3. Nothing else is a binary tree.
A function to compute the height of a binary tree, and one to compute the number of nodes:

fun height Empty = 0
  | height (Node (lft, _, rht)) = 1 + max (height lft, height rht)

fun size Empty = 0
  | size (Node (lft, _, rht)) = 1 + size lft + size rht

Heterogeneous Data Structures

The tree data type above requires that the type of the data items at the nodes must be the same for every node of the tree. To represent a heterogeneous tree, the data item must be labelled with enough info to determine the type at run-time.

datatype int_or_string =
  Int of int |
  String of string

type int_or_string =
  int_or_string tree

Datatype declarations and pattern matching can be useful for manipulating the abstract syntax of a language. Consider an example representing arithmetic expressions:

datatype expr =
  Numeral of int |
  Plus of expr * expr |
  Times of expr * expr

fun eval (Numeral n) = Numeral n
  | eval (Plus (e1, e2)) =
    let
        val Numeral n1 = eval e1
        val Numeral n2 = eval e2
    in
        Numeral (n1+n2)
    end
  | eval (Times (e1, e2)) =
    let
        val Numeral n1 = eval e1
        val Numeral n2 = eval e2
    in
        Numeral (n1*n2)
    end

If we extend the expr datatype as follows:

datatype expr =
  Numeral of int |
  Plus of expr * expr |
  Times of expr * expr
  Recip of expr

The compiler will complain about eval being incompatible with the new version of expr. Recompiling eval will produce an inexhaustive match warning since eval lacks a case for Recip. This is one of the benefits of static typing provided in Standard ML.

Tags: ,

I found a handy article for sending growl notifications from Emacs and made some modifications for my particular setup.

Step One: Register Emacs with Growl
We need to register Carbon Emacs with Growl. This is a one time setup task. The following AppleScript script can be run in Script Editor.

tell application "GrowlHelperApp"
	-- Declare a list of notification types
	set the allNotificationsList to {"Emacs Notification"}

	-- Declare list of active notifications.  If some of them
	-- isn't activated, user can do this later via preferences
	set the enabledNotificationsList to {"Emacs Notification"}

	-- Register our application in Growl.
	register as application "Emacs.app" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "Emacs.app"
end tell

Step Two: Create Growl Notification Script
This is a template of the AppleScript that will be used in the Emacs Lisp function. It can be tested by executing it in the Script Editor.

tell application "GrowlHelperApp"
	notify with name "Emacs Notification" title "Emacs alert" description "Message!!!" application name "Emacs.app"
end tell

Step Three: Emacs Lisp Function
Create an Emacs Lisp function that can be invoked with a title and message.

(defun bja-growl-notification (title message &optional sticky)
  "Send a Growl notification"
  (do-applescript
   (format "tell application \"GrowlHelperApp\"
              notify with name \"Emacs Notification\" title \"%s\" description \"%s\" application name \"Emacs.app\" sticky %s
           end tell"
           title
           (replace-regexp-in-string "\"" "''" message)
           (if sticky "yes" "no"))))

This can be tested with the following function which sends two growl notifications. The “sticky” one requires an explicit dismissal.

(defun bja-growl-test ()
  (interactive)
  (bja-growl-notification "Emacs Notification" "This is my message")
  (bja-growl-notification "Emacs Notification" "This is my sticky message" t))

UPDATE: I noticed bja-growl-notification was failing if the message had embedded double quotes, so I added a call to replace-regexp-in-string to replace them with two apostrophes.

UPDATE 2: My main motivation for setting this up was to be able to generate growl notifications from ERC (Emacs IRC client). However, I quickly realized that having a generic reminder that I can easily fire up from within Emacs is very handy. Here’s the code:

(defun bja-growl-timer (minutes message)
  "Issue a Growl notification after specified minutes"
  (interactive (list (read-from-minibuffer "Minutes: " "10")
                     (read-from-minibuffer "Message: " "Reminder") ))
  (run-at-time (* (string-to-number minutes) 60)
               nil
               (lambda (minutes, message)
                 (bja-growl-notification "Emacs Reminder" message t))
               minutes
               message))

Tags: , ,

The story of Andrew Wiles who solved Fermat’s Last Theorem in 1994.

Tags:

« Older entries