Standard ML interpreter, implemented in Java
Java version 8 or higher.
Get smlj from Maven Central:
<dependency>
<groupId>net.hydromatic</groupId>
<artifactId>smlj</artifactId>
<version>0.1.0</version>
</dependency>$ git clone git://github.com/julianhyde/smlj.git
$ cd smlj
$ ./mvnw installOn Windows, the last line is
> mvnw install$ ./smlj
smlj version 0.1.0 (java version "11.0.4", JLine terminal, xterm-256color)
= "Hello, world!";
val it = "Hello, world!" : string
= exit
$Implemented:
- Literals
- Variables
- Comments (
(* block *)and(*) line) let(expression that lets you define local variables and functions)val(includingval rec)fun(declare function)- Operators:
=<><><=>=~+-*/divmod^andalsoorelse:: - Built-in constants and functions:
ittruefalsenot - Type derivation
fn, function values, and function applicationifcase- Primitive, list, tuple and record types
- Type variables (polymorphism) (but see "bugs")
- Enumerated types (
datatype) - Tuples and unit, record and list values
- Patterns (destructuring) in
valandcase, matching constants, wildcards, lists, records and tuples - Basis library functions:
abs
Not implemented:
typelocalraise,handleexceptionwhile- References, and operators
!and:= - Operators:
@before - Constants:
nil - User-defined operators (
infix,infixr) - Type annotations in expressions and patterns
Bugs:
- Unbound type variables are not yet supported. For example, the
expression
[]should have type'a listbut currently fails - Prevent user from overriding built-in constants and functions:
true,false,nil,ref,it,::; they should not be reserved - Access parameters and variables by offset into a fixed-size array; currently we address them by name, in a map that is copied far too often
- Runtime should throw when divide by zero
- Validator should give good user error when it cannot type an expression
The from expression (and associated as, where and yield keywords)
is a language extension to support relational algebra.
It iterates over a list and generates another list.
In a sense, from is syntactic sugar. For example, given emps and
depts, relations defined as lists of records as follows
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 = "Marketing"},
{deptno = 30, name = "Engineering"},
{deptno = 40, name = "Support"}];
the expression
from e in emps where (#deptno e = 30) yield (#id e)
is equivalent to standard ML
map (fn e => (#id e)) (filter (fn e => (#deptno e) = 30) emps)
with the where and yield clauses emulating the filter and map
higher-order functions without the need for lambdas (fn).
Relational expressions are an experiment bringing the features of query languages such as SQL into a functional language. We believe that a little syntactic sugar, backed by a relational query planner, makes ML into a powerful and convenient tool for querying large data sets. Conversely, we want to see how SQL would look if it supported lambdas, function-values, polymorphism, pattern-matching, and removed the syntactic distinction between tables and collection-valued columns.
You can iterate over more than one collection, and therefore generate a join or a cartesian product:
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)};
As in any ML expression, you can define functions within a from expression,
and those functions can operate on lists. Thus we can implement equivalents of
SQL's IN and EXISTS operators:
let
fun in_ e [] = false
| in_ e (h :: t) = e = h orelse (in_ e t)
in
from e in emps
where in_ (#deptno e) (from d in depts
where (#name d) = "Engineering"
yield (#deptno d))
yield (#name e)
end
let
fun exists [] = false
| exists hd :: tl = 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
In the second query, note that the sub-query inside the exists is
correlated (references the e variable from the enclosing query)
and skips the yield clause (because it doesn't matter which columns
the sub-query returns, just whether it returns any rows).
- License: Apache License, Version 2.0
- Author: Julian Hyde (@julianhyde)
- Project page: https://www.hydromatic.net/smlj
- API: https://www.hydromatic.net/smlj/apidocs
- Source code: https://github.com/julianhyde/smlj
- Developers list: dev at calcite.apache.org (archive, subscribe)
- Issues: https://github.com/julianhyde/smlj/issues
- Release notes and history