diff --git a/standard-ml.html.markdown b/standard-ml.html.markdown
new file mode 100644
index 00000000..d1a8fc12
--- /dev/null
+++ b/standard-ml.html.markdown
@@ -0,0 +1,334 @@
+---
+language: Standard ML
+contributors:
+    - ["Simon Shine", "http://shine.eu.org/"]
+lang: en-en
+---
+
+Standard ML is a functional programming language with type inference and some
+side-effects.  Some of the hard parts of learning Standard ML are: Recursion,
+pattern matching, type inference (guessing the right types but never allowing
+implicit type conversion).  If you have an imperative background, not being able
+to update variables can feel severely inhibiting.
+
+```
+(* Comments in Standard ML begin with (* and end with *).  Comments can be
+   nested which means that all (* tags must end with a *) tag.  This comment
+   contains two nested comments. *)
+
+(* A Standard ML program consists of declarations, e.g. value declarations: *)
+val rent = 1200
+val phone_no = 5551337
+val pi = 3.14159
+val negative_number = ~15  (* Yeah, unary minus is a so-called 'tilde' *)
+
+(* And just as importantly, functions: *)
+fun is_large(x : int) = if x > 37 then true else false
+
+(* Floating-point numbers are called "reals". *)
+val tau = 2.0 * pi         (* You can multiply reals *)
+val twice_rent = 2 * rent  (* You can multiply ints *)
+(* val meh = 1.25 * 10 *)  (* But you can't multiply an int and a real *)
+
+(* +, - and * are overloaded so they work for both int and real. *)
+(* The same cannot be said for division which has separate operators: *)
+val real_division = 14.0 / 4.0  (* gives 3.5 *)
+val int_division  = 14 div 4    (* gives 3, rounding down *)
+val int_remainder = 14 mod 4    (* gives 2, since 3*4 = 12 *)
+
+(* ~ is actually sometimes a function (e.g. when put in front of variables) *)
+val negative_rent = ~(rent)  (* Would also have worked if rent were a "real" *)
+
+(* There are also booleans and boolean operators *)
+val got_milk = true
+val got_bread = false
+val has_breakfast = got_milk andalso got_bread  (* Yes, it's called andalso *)
+val has_something = got_milk orelse got_bread   (* Yes, it's called orelse *)
+val is_sad = not(has_something)                 (* not is a function *)
+
+(* Many values can be compared using equality operators: = and <> *)
+val pays_same_rent = (rent = 1300)  (* false *)
+val is_wrong_phone_no = (phone_no <> 5551337)  (* false *)
+
+(* The operator <> is what most other languages call != *)
+
+
+(* Actually, most of the parentheses above are unnecessary.  Here are some
+   different ways to say some of the things mentioned above: *)
+fun is_large x = x > 37  (* The parens above were necessary because of ': int' *)
+val is_sad = not has_something
+val pays_same_rent = rent = 1300  (* Looks confusing, but works *)
+val is_wrong_phone_no = phone_no <> 5551337
+val negative_rent = ~rent  (* ~ rent (notice the space) would also work *)
+
+(* Parens are mostly necessary when grouping things: *)
+val some_answer = is_large (5 + 5)      (* Without parens, this would break! *)
+(* val some_answer = is_large 5 + 5 *)  (* Read as: (is_large 5) + 5. Bad! *)
+
+
+(* Besides booleans, ints and reals, Standard ML also has chars and strings: *)
+val foo = "Hello, World!\n"  (* The \n is the escape sequence for linebreaks *)
+val one_letter = #"a"        (* That funky syntax is just one character, a *)
+
+val combined = "Hello " ^ "there, " ^ "fellow!\n"  (* Concatenate strings *)
+
+val _ = print foo       (* You can print things. We are not interested in the *)
+val _ = print combined  (* result of this computation, so we throw it away. *)
+(* val _ = print one_letter *)  (* Only strings can be printed this way *)
+
+
+val bar = [ #"H", #"e", #"l", #"l", #"o" ]  (* SML also has lists! *)
+(* val _ = print bar *)  (* Lists are unfortunately not the same as strings *)
+
+(* Fortunately they can be converted.  String is a library and implode and size
+   are functions available in that library that take strings as argument. *)
+val bob = String.implode bar          (* gives "Hello" *)
+val bob_char_count = String.size bob  (* gives 5 *)
+val _ = print (bob ^ "\n")  (* For good measure, add a linebreak *)
+
+(* You can have lists of any kind *)
+val numbers = [1, 3, 3, 7, 229, 230, 248]  (* : int list *)
+val names = [ "Fred", "Jane", "Alice" ]    (* : string list *)
+val groups = [ [ "Alice", "Bob" ],
+               [ "Huey", "Dewey", "Louie" ],
+               [ "Bonnie", "Clyde" ] ]     (* : string list list *)
+
+val number_count = List.length numbers     (* gives 7 *)
+
+(* You can put single values in front of lists of the same kind *)
+val more_numbers = 13 :: numbers  (* gives [13, 1, 3, 3, 7, ...] *)
+val more_groups  = ["Batman","Superman"] :: groups
+
+(* Lists of the same kind can be appended using the @ ("append") operator *)
+val guest_list = [ "Mom", "Dad" ] @ [ "Aunt", "Uncle" ]
+
+(* This could have been done with the :: operator (pronounced "cons") *)
+val guest_list = "Mom" :: "Dad" :: [ "Aunt", "Uncle" ]
+
+(* If you have many lists of the same kind, you can concatenate them all *)
+val everyone = List.concat groups  (* [ "Alice", "Bob", "Huey", ... ] *)
+
+(* A list can contain any (finite) amount of values *)
+val lots = [ 5, 5, 5, 6, 4, 5, 6, 5, 4, 5, 7, 3 ]  (* still just an int list *)
+
+(* Lists can only contain one kind of thing... *)
+(* val bad_list = [ 1, "Hello", 3.14159 ] : ??? list *)
+
+
+(* Tuples, on the other hand, can contain a fixed number of different things *)
+val person1 = ("Simon", 28, 3.14159)  (* : string * int * real *)
+
+(* You can even have tuples inside lists and lists inside tuples *)
+val likes = [ ("Alice", "ice cream"),
+              ("Bob",   "hot dogs"),
+              ("Bob",   "Alice") ]     (* : (string * string) list *)
+
+val mixup = [ ("Alice", 39),
+              ("Bob",   37),
+              ("Eve",   41) ]  (* : (string * int) list *)
+
+val good_bad_stuff =
+  (["ice cream", "hot dogs", "chocolate"],
+   ["liver", "paying the rent" ])           (* string list * string list *)
+
+
+(* Functions! *)
+fun add_them (a, b) = a + b    (* A simple function that adds two numbers *)
+val test_it = add_them (3, 4)  (* gives 7 *)
+
+(* Larger functions are usually broken into several lines for readability *)
+fun thermometer temp =
+    if temp < 37
+    then "Cold"
+    else if temp > 37
+         then "Warm"
+         else "Normal"
+
+val test_thermo = thermometer 40  (* gives "Warm" *)
+
+(* if-sentences are actually expressions and not statements/declarations.
+   A function body can only contain one expression.  There are some tricks
+   for making a function do more than just one thing, though. *)
+
+(* A function can call itself as part of its result (recursion!) *)
+fun fibonacci n =
+    if n = 0 then 0 else                   (* Base case *)
+    if n = 1 then 1 else                   (* Base case *)
+    fibonacci (n - 1) + fibonacci (n - 2)  (* Recursive case *)
+
+(* Sometimes recursion is best understood by evaluating a function by hand:
+
+ fibonacci 4
+   ~> fibonacci (4 - 1) + fibonacci (4 - 2)
+   ~> fibonacci 3 + fibonacci 2
+   ~> (fibonacci (3 - 1) + fibonacci (3 - 2)) + fibonacci 2
+   ~> (fibonacci 2 + fibonacci 1) + fibonacci 2
+   ~> ((fibonacci (2 - 1) + fibonacci (2 - 2)) + fibonacci 1) + fibonacci 2
+   ~> ((fibonacci 1 + fibonacci 0) + fibonacci 1) + fibonacci 2
+   ~> ((1 + fibonacci 0) + fibonacci 1) + fibonacci 2
+   ~> ((1 + 0) + fibonacci 1) + fibonacci 2
+   ~> (1 + fibonacci 1) + fibonacci 2
+   ~> (1 + 1) + fibonacci 2
+   ~> 2 + fibonacci 2
+   ~> 2 + (fibonacci (2 - 1) + fibonacci (2 - 2))
+   ~> 2 + (fibonacci (2 - 1) + fibonacci (2 - 2))
+   ~> 2 + (fibonacci 1 + fibonacci 0)
+   ~> 2 + (1 + fibonacci 0)
+   ~> 2 + (1 + 0)
+   ~> 2 + 1
+   ~> 3  which is the 4th Fibonacci number, according to this definition
+
+ *)
+
+(* A function cannot change the variables it can refer to.  It can only
+   temporarily shadow them with new variables that have the same names.  In this
+   sense, variables are really constants and only behave like variables when
+   dealing with recursion.  For this reason, variables are also called value
+   bindings.  An example of this: *)
+
+val x = 42
+fun answer(question) =
+    if question = "What is the meaning of life, the universe and everything?"
+    then x
+    else raise Fail "I'm an exception. Also, I don't know what the answer is."
+val x = 43
+val hmm = answer "What is the meaning of life, the universe and everything?"
+(* Now, hmm has the value 42.  This is because the function answer refers to
+   the copy of x that was visible before its own function definition. *)
+
+
+(* Functions can take several arguments by taking one tuples as argument: *)
+fun solve2 (a : real, b : real, c : real) =
+    ( Math.sqrt (~b + Math.sqrt(b * b - 4.0*a*c) / (2.0 * a),
+      Math.sqrt (~b - Math.sqrt(b * b - 4.0*a*c) / (2.0 * a) )
+
+(* Sometimes, the same computation is carried out several times. It makes sense
+   to save and re-use the result the first time. We can use "let-bindings": *)
+fun solve2 (a : real, b : real, c : real) =
+    let val discr  = b * b - 4.0*a*c
+        val sqr = Math.sqrt d
+        val denom = 2.0 * a
+    in (~b + sq / denom,
+        ~b - sq / denom) end
+
+
+(* Pattern matching is a funky part of functional programming.  It is an
+   alternative to if-sentences.  The fibonacci function can be rewritten: *)
+fun fibonacci 0 = 0  (* Base case *)
+  | fibonacci 1 = 1  (* Base case *)
+  | fibonacci n = fibonacci (n - 1) + fibonacci (n - 2)  (* Recursive case *)
+
+(* Pattern matching is also possible on composite types like tuples and lists.
+   Writing "fun solve2 (a, b, c) = ..." is in fact a pattern match on the one
+   three-tuple solve2 takes as argument. Similarly, but less intuitively, you
+   can match on a list consisting of elements in it (from the beginning of the
+   list only). *)
+fun first_elem (x::xs) = x
+fun second_elem (x::y::xs) = y
+fun evenly_positioned_elems (odd::even::xs) = even::evenly_positioned_elems xs
+  | evenly_positioned_elems [odd] = []  (* Base case: throw away *)
+  | evenly_positioned_elems []    = []  (* Base case *)
+
+
+(* Higher order functions: Functions can take other functions as arguments.
+   Functions are just other kinds of values, and functions don't need names
+   to exist.  Functions without names are called "anonymous functions" or
+   lambda expressions or closures (since they also have a lexical scope). *)
+val is_large = (fn x => x > 37)
+val add_them = fn (a,b) => a + b
+val thermometer =
+    fn temp => if temp < 37
+               then "Cold"
+               else if temp > 37
+                    then "Warm"
+                    else "Normal"
+
+(* The following uses an anonymous function directly and gives "ColdWarm" *)
+val some_result = (fn x => thermometer (x - 5) ^ thermometer (x + 5)) 37
+
+(* Here is a higher-order function that works on lists (a list combinator) *)
+val readings = [ 34, 39, 37, 38, 35, 36, 37, 37, 37 ]  (* first an int list *)
+val opinions = List.map thermometer readings (* gives [ "Cold", "Warm", ... ] *)
+
+(* And here is another one for filtering lists *)
+val warm_readings = List.filter is_large readings  (* gives [39, 38] *)
+
+(* You can create your own higher-order functions, too.  Functions can also take
+   several arguments by "currying" them. Syntax-wise this means adding spaces
+   between function arguments instead of commas and surrounding parentheses. *)
+fun map f [] = []
+  | map f (x::xs) = f(x) :: map f xs
+
+(* map has type ('a -> 'b) -> 'a list -> 'b list and is called polymorphic. *)
+(* 'a is called a type variable. *)
+
+(* Datatypes are useful for creating both simple and complex structures *)
+datatype color = Red | Green | Blue
+
+(* Here is a function that takes one of these as argument *)
+fun say(col) =
+    if col = Red then "You are red!" else
+    if col = Green then "You are green!" else
+    if col = Blue then "You are blue!" else
+    raise Fail "Unknown color"
+
+(* Datatypes are very often used in combination with pattern matching *)
+fun say Red = "You are red!"
+  | say Green = "You are green!"
+  | say Blue = "You are blue!"
+  | _ = raise Fail "Unknown color"
+
+
+(* Here is a binary tree datatype *)
+datatype 'a btree = Leaf of 'a
+                  | Node of 'a btree * 'a * 'a btree (* three-arg constructor *)
+
+(* Here is a binary tree *)
+val myTree = Node (Leaf 9, 8, Node (Leaf 3, 5, Leaf 7))
+
+(* Drawing it, it might look something like...
+
+           8
+          / \
+ leaf -> 9   5
+            / \
+   leaf -> 3   7 <- leaf
+ *)
+
+(* This function counts the sum of all the elements in a tree *)
+fun count (Leaf n) = n
+  | count (Node (leftTree, n, rightTree)) = count leftTree + n + count rightTree
+
+
+(* File I/O! *)
+(* Write a nice poem to a file *)
+fun writePoem(filename) =
+    let val file = TextIO.openOut(filename)
+        val _ = TextIO.output(file, "Roses are red,\nViolets are blue.\n")
+        val _ = TextIO.output(file, "I have a gun.\nGet in the van.\n")
+    in TextIO.closeOut(file) end
+
+(* Read a nice poem from a file into a list of strings *)
+fun readPoem(filename) =
+    let val file = TextIO.openIn filename
+        val poem = TextIO.inputAll file
+        val _ = TextIO.closeIn file
+    in String.tokens (fn c => c = #"\n") poem
+    end
+
+val _ = writePoem "roses.txt"
+val test_poem = readPoem "roses.txt"  (* gives [ "Roses are red,",
+                                                 "Violets are blue.",
+                                                 "I have a gun.",
+                                                 "Get in the van." ] *)
+~~~~
+
+## Further learning
+
+* Install an interactive compiler (REPL), for example
+  [http://www.polyml.org/](Poly/ML),
+  [http://mosml.org](Moscow ML) or
+  [http://smlnj.org/](SML/NJ).
+* Follow the Coursera course [Programming Languages](https://www.coursera.org/course/proglang).
+* Get the book *ML for the Working Programmer* by Larry C. Paulson.
+