learning emacs incrementally

I’m taking a Coursera course that encourages using emacs as an editor. I’ve been fluent in vi for over a decade so this seemed like a good time to try out emacs. You don’t actually need to use emacs for the class; it is just adding syntax highlighting. However, being minimally functional in emacs happened within two hours. And that was focusing on sml and not emacs. The idea is to become minimally functional quickly and then add “optimizations” to become faster.

Minimally functional commands:

Note that C means Control and M means meta (which is the escape key on the mac rather than alt – annoying because I can touch type alt but not escape)

  1. C-x, C-f – open a file
  2. C-x, C-s – save current file – I use this one a lot!
  3. C-x, C-c – quit emacs
  4. C-x 0 (that is a zero) – close the current split window and merge into one
  5. C-x o (that is a lower case o) – switch between split windows
  6. C-x 2 – split into two buffers – I actually stopped using this pretty quickly as I found it easier to have two tabs with emacs open.  I’ve seen multiple buffers used very effectively though.
  7. C-c, C-s – open sml RPEL – I stopped using this quickly as well
  8. Cx Cc – prompt to save and exit
  9. C-D – restart RPEL – stopped using as well
  10. M-p -previous RPEL – stopped using as well

Second iteration of using emacs better – navigating with the keyboard

  1. C-a – beginning of line
  2. C-e – end of line
  3. C-v – page down
  4. M-v page up – note must re-press escape each time
  5. C-s – regular expression search

Third iteration

  1. C-k – delete to end of line
  2. M < – beginning of file (yes that is escape + shift + , on a mac
  3. M > – end of file

And that’s as far as I got.  I was able to have “emacs” not get in my way with just this.  I can’t even call what I did learning emacs since I know there are many features that would make it more efficient.  But it was enough for the class.  And then I go back to vi.

smlunit – using without a python dependency

I’m currently taking the Coursera Programming Languages course which starts with ML.  Or more specifically SML/NJ.

Why I was looking at unit testing in SML

The instructor gave a test file with statements like:

val foo = function_to_write(1) = 2;

This is good in that it clearly shows the API and some of the expectations.  It’s not so good because you have to go thru the output to look whether all the values are set to true.  We were provided with 11 tests and told to write more.  I had 57 by the time I was done.  And I haven’t looked at the two challenge problems yet.  The instructor was very direct in saying we shouldn’t compare SML to languages we know because it impedes learning.  Well, I didn’t.  I compared the infrastructure.  And I learned more SML learning how this works than covered in week 1 of the class so I think I honored the spirit of this.

Choosing a SMLUnit implementation

I found two options in search

  1. SML Sharp‘s SML Unit – I found more references to this one on the internet.  However it requires steps to install and looks like it takes longer to get started with.
  2. SML Unit – This is the #1 hit on google for SML Unit and appears to be something written by a university student.  It’s very good though and I recommend it.

Python dependency

SMLUnit comes with good documentation and examples.  It also comes with a runner that uses Python to kick off the tests and report on the status.  This can’t be done purely in SML because reporting on the results requires state.

I’m sure it is a good runner, but I didn’t notice it existed.  (I started on the code page with the assertions not the main page that explains all this.)  Since I went to the (minor) trouble to create a runner in UNIX,  I’m posting it in case anyone wants to test SML on a machine that doesn’t have Python.  Not likely I know – most machines have Python.

The runner

The runner feeds your unit tests to SML and then reports on whether there were any failures.


# Since sml is a functional language, I couldn't figure out a way to output a summary
# at the end as to whether any tests failed. Wrapping in a shell script to avoid
# this problem. [realized afterwards it comes with a Python runner]
#
# Usage:
# smlunit_runner.sh name_of_tests.sml
#
# Assumes the sml test suite has "use" statements for all dependencies including smlunit

if [ $# -eq 0 ]
then
 echo "SML test file is mandatory"
 exit
fi

OUTPUT=`cat $1 | /usr/local/smlnj/bin/sml`

echo "$OUTPUT"

NUM_FAIL=`echo "$OUTPUT" | grep "^FAIL$" | wc -l`
NUM_PASS=`echo "$OUTPUT" | grep "^OK$" | wc -l`

echo ""
echo ""
echo "Test summary: (also look at last output to make sure not a stack trace)"
echo "$NUM_FAIL tests failed"
echo "$NUM_PASS tests passed"

What do the tests look like?

Code – helloWorld.sml

fun hello_world() = "hello"

fun add(a:int, b:int) = a + b

Tests – helloWorldTest.sml

use "asserts.sml";

<em id="__mceDel">use "helloWorld.sml";</em>

assertTrue true "assert true";
assertEqual "hello" (hello_world()) "compare two values";
assertEqual 3 (add(1,2)) "compare two values again";

And what about the asserts?

asserts.sml is a direct copy of smlunit.sml


(* from https://github.com/dellsystem/smlunit/blob/master/lib/smlunit.sml *)

fun roundish (x:real) = Real.realRound(x * 100000000000.0) / 100000000000.0;

fun assert expr1 expr2 (desc:string) function =
 (print ("*********** " ^ desc ^ " ***********\n" );
 (if function (expr1, expr2) then
 print "OK\n"
 else
 print "FAIL\n"
 );
 [expr1, expr2]);

fun assertEqual expr1 expr2 (desc:string) = assert expr1 expr2 desc (fn (x, y) => x = y);
fun assertRealEqual (expr1:real) (expr2:real) (desc:string) = assert expr1 expr2 desc (fn (x, y) => Real.== (roundish(x), roundish(y)));

fun assertTrue expr desc = (assertEqual expr true desc);
fun assertFalse expr desc = (assertEqual expr false desc);

(* Functions for comparing a lot of things in one list *)
fun assertReals f [] (desc:string) = []
 | assertReals f ((input, output, expl)::t) (desc:string) =
 (assertRealEqual (f input) output (desc ^ ": " ^ expl)) @ (assertReals f t (desc));

fun assertRegulars f [] (desc:string) = []
 | assertRegulars f ((input, output, expl)::t) (desc:string) =
 (assertEqual (f input) output (desc ^ ": " ^ expl)) @ (assertRegulars f t (desc));

Comments?

I have less than 5 hours experience with SML   (I did know LISP in college and recursion certainly isn’t new.)  So I’m sure there are naming conventions and the like that I’m not following.  I look forward to hearing comments on what I did.