# sleep 2
# This is a demo to introduce smlj.
#
# smlj is a Java implementation of Standard ML: a small,
# elegant functional programming language based on typed
# lambda calculus. It has inspired many other languages,
# including Haskell and Scala.
#
# Later in the demo, we show some relational algebra
# extensions: with "from" expressions, smlj becomes a
# powerful query language.
#
# To start, let's download and build smlj.
git clone git@github.com:julianhyde/smlj.git -b 004-cast
# sleep 10

cd smlj
./mvnw -DskipTests install
# sleep 20

./smlj
# sleep 10

# sleep 3
(*) Now we're in smlj's shell, for interactive commands.
(*) First of all, we need to talk about comments.

(* This is a block comment, which can span multiple lines... *)

(*) ... and this is a single-line comment.

(*) Now, the basics.
(*) Everything in ML is an expression.
"a string literal";
1 + 2;

(*) The smlj shell deduces the type of each expression,
(*) and assigns it to a variable called "it".
(*) We can use "it" in the next expression...
it + 4;

(*) We just saw string and int expressions.
(*) There are also boolean, list, record and tuple types:
1 = 2;
[1, 2, 3];
{id = 10, name = "Alex"};
(1, true, "yes");

(*) You can assign values to variables.
val x = 7;
val y =  x mod 3;

(*) Functions are expressions, too.
(*) "fn" makes a lambda expression.
val plusOne = fn x => x + 1;
plusOne 2;

(*) Functions are widely used, so they have a shorthand.
(*) "fun" is short for "val ... = fn".
fun plusOne x = x + 1;
plusOne 1000;

(*) Functions can have multiple arguments, separated by spaces.
fun plus x y = x + y;
plus 3 4;

(*) If we supply too few arguments, we get a closure that captures
(*) the argument value and can be applied later.
val plusTen = plus 10;
plusTen 2;

(*) Functions can be recursive.
fun fact n = if n = 1 then 1 else n * fact (n - 1);
fact 1;
fact 5;

(*) A higher-order function is a function that operates on other
(*) functions. Here are a couple.

(*) "map" applies another function to each element of a list
let
  fun map f [] = []
    | map f (head :: tail) = (f head) :: (map f tail)
  fun double n = n * 2
in
  map double [1, 2, 3, 4]
end;

(*) "filter" keeps only those elements of a list for which
(*) a predicate evaluates to true.
let
  fun filter p [] = []
    | filter p (head :: tail) =
      if (p head) then
        (head :: (filter p tail))
      else
        (filter p tail)
  fun even n = n mod 2 = 0
in
  filter even [1, 2, 3, 4]
end;

(*) You may notice that "map" and "filter" are very similar to the
(*) "select" and "where" clauses of a SQL statement.
(*)
(*) This is no surprise: relational algebra, which underlies SQL, is
(*) basically a collection of higher-order functions applied to
(*) lists of records (relations).
(*)
(*) Can we extend ML syntax to make it easier to write relational
(*) algebra expressions? You bet!

(*) Let's start by defining "emp" and "dept" relations as lists of
(*) records.
val emps =
  [{id = 100, name = "Fred", deptno = 10},
   {id = 101, name = "Velma", deptno = 20},
   {id = 102, name = "Shaggy", deptno = 30},
   {id = 103, name = "Scooby", deptno = 30}];
val depts =
  [{deptno = 10, name = "Sales"},
   {deptno = 20, name = "HR"},
   {deptno = 30, name = "Engineering"},
   {deptno = 40, name = "Support"}];

(*) Now our first query, equivalent to "select * from emps as e".
from e in emps yield e;

(*) Now "select e.id from emps as e where e.deptno = 30"
from e in emps where (#deptno e) = 30 yield (#id e);

(*) Join two relations
from e in emps, d in depts
  where (#deptno e) = (#deptno d)
  yield {id = (#id e), deptno = (#deptno e),
         ename = (#name e), dname = (#name d)};

(*) A query with "exists" and a correlated sub-query.
(*) We define the "exists" function ourselves: no need for a
(*) built-in!
let
  fun exists [] = false
    | exists (head :: tail) = true
in
  from e in emps
    where exists (from d in depts
                  where (#deptno d) = (#deptno e)
                  andalso (#name d) = "Engineering")
    yield (#name e)
end;

(*) That's all, folks!
(*) To recap, smlj has:
(*)  * expressions of int, string, boolean, float, char, list,
(*)    tuple and record types;
(*)  * lambda expressions and recursive functions;
(*)  * algebraic datatypes and pattern-matching;
(*)  * polymorphism and powerful type-inference;
(*)  * relational expressions (an extension to Standard ML).
(*)
(*) Follow our progress at https://github.com/julianhyde/smlj.
(*) This is only release 0.1, so there's more to come!

# sleep 2
exit
exit
