100 Helloslanguages
Home / Languages / Standard ML

Standard ML

1983fraglet
ml-familyfunctional.sml.sig
docker run --rm --platform="linux/amd64" 100hellos/sml:latest

MCP + fragletc

MCPstdinargs
This language supports code execution via MCP and the fragletc CLI. Stdin piping and argument passing are both supported.
Install fragletc โ†’

Standard ML (SML) is a general-purpose, modular, functional programming language with compile-time type checking and type inference. Developed in the 1980s, it's known for its mathematical foundations and elegant design.

About Standard ML

Standard ML was designed as a meta-language for the Edinburgh LCF theorem prover, but evolved into a standalone programming language. It features:

  • Strong static typing with Hindley-Milner type inference
  • Functional programming with immutable data structures by default
  • Pattern matching for elegant control flow
  • Module system for large-scale program organization
  • Formal semantics - one of the few languages with a complete formal definition

This Implementation

This container uses Poly/ML, a full implementation of Standard ML that's particularly well-suited for interactive development and deployment. Poly/ML is compatible with musl libc, making it perfect for Alpine Linux containers.

Fun Facts

  • Standard ML has influenced many modern languages including OCaml, Haskell, and Rust
  • It was one of the first languages to feature garbage collection and polymorphic type inference
  • The language definition fits in a relatively small book, yet it's computationally complete
  • Robin Milner, one of SML's creators, won the Turing Award partly for his work on type systems

Language Features Showcase

(* This simple "Hello World!" demonstrates SML's clean syntax *)
print "Hello World!\n";

(* But SML can do much more with functions and pattern matching *)
fun factorial 0 = 1
  | factorial n = n * factorial (n - 1);

(* Polymorphic data structures *)
datatype 'a option = NONE | SOME of 'a;

SML proves that functional programming can be both mathematically rigorous and practically useful!

Hello World

#!/usr/bin/env sh

# If this file is present, this is the file that runs when you add the
# RUN=1 option.
#
# Otherwise, the default behavior is to run the first file in the
# directory that matches the pattern `hello-world.*``.

# Build it
# Run it

poly -q --use /hello-world/hello-world.sml "$@"

Coding Guide

Language Version

Poly/ML 5.x (Standard ML implementation)

Execution Model

  • Interpreted via Poly/ML REPL
  • Code executes at the top level
  • Expressions and declarations run immediately
  • Uses poly --quiet to suppress startup messages

Key Characteristics

  • Strong static typing with Hindley-Milner type inference
  • Functional programming with immutable data structures by default
  • Pattern matching for elegant control flow
  • Case-sensitive identifiers
  • Semicolon-terminated statements and declarations
  • Top-level bindings - functions and values can be defined at module level

Fragment Authoring

Write valid SML expressions or declarations. Your fragment becomes the script body. Code executes at the top level, so expressions run immediately. You can define functions, values, and use pattern matching.

Available Libraries

Standard ML Basis Library is available. Poly/ML provides additional libraries for I/O, system interaction, and more.

Common Patterns

print "Hello, World!\n";

Variable Bindings

val x = 42;
val name = "Alice";
print (name ^ "\n");

Function Definitions

fun greet name = "Hello, " ^ name ^ "!\n";
print (greet "World");

Pattern Matching

fun factorial 0 = 1
  | factorial n = n * factorial (n - 1);
print ("Factorial of 5: " ^ Int.toString (factorial 5) ^ "\n");

Lists and Higher-Order Functions

val numbers = [1, 2, 3, 4, 5];
val sum = foldl (op +) 0 numbers;
print ("Sum: " ^ Int.toString sum ^ "\n");

Recursive Functions

fun length [] = 0
  | length (_::xs) = 1 + length xs;
print ("Length: " ^ Int.toString (length [1,2,3]) ^ "\n");

Conditional Expressions

fun max a b = if a > b then a else b;
print ("Max of 5 and 10: " ^ Int.toString (max 5 10) ^ "\n");

Examples

# Simple output
print "Hello, World!\n";

# Variables and calculations
val a = 5;
val b = 10;
print ("Sum: " ^ Int.toString (a + b) ^ "\n");

# Function definition
fun add x y = x + y;
print ("5 + 10 = " ^ Int.toString (add 5 10) ^ "\n");

# Pattern matching
fun factorial 0 = 1
  | factorial n = n * factorial (n - 1);
print ("Factorial of 5: " ^ Int.toString (factorial 5) ^ "\n");

# Lists and higher-order functions
val numbers = [1, 2, 3, 4, 5];
val sum = foldl (op +) 0 numbers;
print ("Sum: " ^ Int.toString sum ^ "\n");

# List comprehensions (using map)
val squares = map (fn x => x * x) [1, 2, 3, 4, 5];
print ("Squares: " ^ String.concatWith ", " (map Int.toString squares) ^ "\n");

# String operations
val s = "Hello";
val t = s ^ " World!";
print (t ^ "\n");
print ("Length: " ^ Int.toString (String.size t) ^ "\n");

# Guards and case expressions
fun absolute x = if x >= 0 then x else ~x;
print ("Absolute of ~5: " ^ Int.toString (absolute (~5)) ^ "\n");

I/O Patterns

Stdin

fun loop () =
    case TextIO.inputLine TextIO.stdIn of
        NONE => ()
      | SOME s => (print (String.map Char.toUpper s); loop ());
loop ();

Command-Line Arguments

CommandLine.arguments() includes 3 internal interpreter arguments before your arguments. Use List.drop to skip them:

val allArgs = CommandLine.arguments ();
val args = List.drop (allArgs, 3);
print ("Args: " ^ String.concatWith " " args ^ "\n");

Caveats and Limitations

  • Semicolons required: Top-level expressions must end with semicolons
  • Type inference: SML infers types, but type errors will prevent execution
  • Immutable by default: Variables are immutable (use val bindings)
  • String concatenation: Use ^ operator, not +
  • Integer negation: Use ~ prefix, not - (e.g., ~5 not -5)
  • Print formatting: Use Int.toString, Real.toString, etc. for number-to-string conversion
  • Poly/ML specific: Some features may be Poly/ML-specific rather than pure SML
  • Program exits automatically after your fragment โ€” do not call OS.Process.exit

Fraglet Scripts

Echo Args

#!/usr/bin/env -S fragletc --vein=sml
val allArgs = CommandLine.arguments ();
val args = List.drop (allArgs, 3);
val () = print ("Args: " ^ String.concatWith " " args ^ "\n");

Stdin Upper

#!/usr/bin/env -S fragletc --vein=sml
fun loop () =
    case TextIO.inputLine TextIO.stdIn of
        NONE => ()
      | SOME s => (print (String.map Char.toUpper s); loop ());
val () = loop ();

Test

#!/usr/bin/env -S fragletc --vein=sml
val () = print "Hello World!\n";

Connections

influenced by

Container Info

image100hellos/sml:latest
build scheduleMonday
fragletenabled