Hello World in Standard ML
Your first Standard ML program - the classic Hello World example with Docker setup using SML/NJ
Every programming journey starts with Hello World. Let’s write our first Standard ML program and explore what makes this influential functional language special.
The Code
Create a file named hello.sml:
| |
That’s it! Just one line for a complete Standard ML program.
Understanding the Code
Let’s break down this simple program:
The print Function
| |
print- A built-in function of typestring -> unitthat outputs a string to standard output"Hello, World!\n"- The string to print (with\nfor newline);- Terminates the expression (required in source files at the top level)
Function Application in SML
Like other ML-family languages, SML uses space for function application:
| |
The Entry Point
Standard ML doesn’t have a main function. Instead, expressions at the top level of a file are evaluated in order when the file is loaded. The program runs by evaluating these top-level bindings.
For clearer intent, you can write:
| |
The val () = ... pattern explicitly shows that we’re executing a side effect that returns unit (similar to void in other languages).
Running with Docker
The easiest way to run Standard ML without installing anything locally is with Docker:
| |
Understanding the Docker Command
docker run --rm- Run a container and remove it when done-v $(pwd):/app- Mount the current directory to/appin the container-w /app- Set the working directory to/appeldesh/smlnj:latest- Use the SML/NJ Docker imagesml hello.sml- Run the SML interpreter on our file
What You’ll See
When you run the program, SML/NJ will display:
Standard ML of New Jersey (64-bit) v110.99.3 [built: ...]
[opening hello.sml]
Hello, World!
val it = () : unit
The interpreter shows:
- Version information
- The file being opened
- Your program’s output
- The result type (
unit)
Expected Output
Hello, World!
Alternative Approaches
Standard ML provides several ways to output text:
Using print with Concatenation
| |
The ^ operator concatenates strings.
Using TextIO for More Control
| |
TextIO provides more fine-grained control over I/O streams.
Formatted Output with Concat
| |
Multiple Statements
| |
Parentheses group sequential expressions, separated by semicolons.
The Unit Type
In Standard ML, every expression has a type. The print function has type:
| |
This means:
- It takes a
stringas input - It returns
unit(written())
The unit type is SML’s equivalent of void - it represents “no meaningful value.” It’s the return type of functions that exist only for their side effects.
| |
Type Inference in Action
Standard ML automatically infers types:
| |
You can check types in the REPL:
- print;
val it = fn : string -> unit
- "Hello";
val it = "Hello" : string
Common Beginner Mistakes
Forgetting the Semicolon
In source files, top-level expressions need semicolons:
| |
Wrong String Quotes
| |
Note: SML uses #"c" syntax for character literals, not just 'c'.
Forgetting the Newline
| |
Mixing Up = and ==
| |
Installing Standard ML Locally
If you prefer to run SML without Docker:
macOS with Homebrew
| |
Ubuntu/Debian
| |
From Source (SML/NJ)
Visit smlnj.org for installation instructions.
After installation:
| |
MLton (Compiled)
For compiled executables, use MLton:
| |
MLton produces highly optimized native code but requires a complete program (no REPL).
The REPL
SML has an excellent interactive environment. Enter sml at the command line:
Standard ML of New Jersey (64-bit) v110.99.3
-
- print "Hello, World!\n";
Hello, World!
val it = () : unit
- 1 + 2;
val it = 3 : int
- fun double x = x * 2;
val double = fn : int -> int
- double 21;
val it = 42 : int
- map double [1, 2, 3];
val it = [2, 4, 6] : int list
The - is the SML prompt. Commands:
- Expressions are terminated with
; - Type Ctrl+D or
OS.Process.exit OS.Process.success;to exit use "file.sml";to load a file
A Bit of History
Standard ML represents a pivotal moment in programming language design:
- 1972 - Robin Milner creates ML for the LCF proof assistant at Stanford
- 1978 - Luca Cardelli creates the first standalone ML compiler
- 1983 - Milner begins standardizing ML
- 1986 - SML/NJ development begins at Bell Labs
- 1990 - The Definition of Standard ML published
- 1997 - Revised Definition published
Standard ML’s formal definition influenced how we think about programming languages. Its type system, module system, and pattern matching appear in nearly every modern functional language.
Why Standard ML for Hello World?
Even in this simple program, you see SML’s philosophy:
- Simplicity - One line does the job
- Explicit Effects -
unitreturn type makes side effects clear - Type Safety - The compiler ensures
printreceives a string - Functional Foundation - Functions are the primary building blocks
- No Boilerplate - No class definitions or main methods needed
Next Steps
Continue to the next tutorial to learn about Standard ML’s powerful type system and pattern matching.
Key Takeaways
printoutputs a string (add\nfor newline)- Function application uses space, not parentheses
;terminates top-level expressions in source filesval () = ...is idiomatic for side-effecting expressionsunit(written()) is SML’s void type- Type inference means you rarely need type annotations
- The REPL is great for experimentation
Running Today
All examples can be run using Docker:
docker pull eldesh/smlnj:latest