Beginner

Hello World in Clojure

Your first Clojure program - the classic Hello World example with Docker setup

Every programming journey starts with Hello World. Let’s write our first Clojure program and discover the elegance of this modern Lisp.

The Code

Create a file named hello.clj:

1
(println "Hello, World!")

Understanding the Code

That’s it! Just one line. Let’s break down what’s happening:

  • (println "Hello, World!") - In Clojure (and all Lisps), code is written as lists using parentheses. The first element is the function name, followed by arguments.
  • println - A built-in function that prints its arguments to the console with a newline.
  • "Hello, World!" - A string literal, just like in most languages.

The Lisp Syntax

Clojure uses prefix notation (also called Polish notation). Instead of writing:

println("Hello, World!")  // Most languages

You write:

1
(println "Hello, World!")  ; Clojure

The function name comes first, inside the parentheses. This uniform syntax is what makes Lisp so powerful and homoiconic (code is data).

Running with Docker

The easiest way to run this without installing Clojure locally:

1
2
3
4
5
# Pull the Clojure Docker image
docker pull clojure:latest

# Run the program
docker run --rm -v $(pwd):/app -w /app clojure:latest clojure hello.clj

Running Locally

If you have Clojure installed:

1
2
3
4
5
6
# Run the script directly
clojure hello.clj

# Or use the lein repl
lein repl
# Then type: (println "Hello, World!")

Expected Output

Hello, World!

Alternative Approaches

Using the Main Function

For a more structured program, you can define a main function:

1
2
3
4
(defn -main []
  (println "Hello, World!"))

(-main)
  • defn - Defines a function
  • -main - By convention, -main is the entry point for applications
  • [] - Empty parameter list
  • The last line calls the function

As a Namespace

For larger programs, you’d typically organize code in namespaces:

1
2
3
4
5
6
(ns hello-world.core)

(defn -main
  "A simple Hello World program"
  [& args]
  (println "Hello, World!"))
  • ns - Declares a namespace
  • "A simple..." - Documentation string (docstring)
  • [& args] - Variable argument list (like *args in Python)

Key Concepts

  1. Prefix Notation - Functions come first: (function arg1 arg2)
  2. Homoiconicity - Code is data; Clojure programs are made of Clojure data structures
  3. Simplicity - The simplest program is just one expression
  4. REPL-Driven - Clojure is designed for interactive development
  5. JVM Language - Clojure compiles to Java bytecode and runs on the JVM

Clojure vs Other Languages

Compare Clojure to similar languages:

Java:

1
2
3
4
5
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Python:

1
print("Hello, World!")

Clojure:

1
(println "Hello, World!")

Notice how Clojure is as concise as Python but runs on the JVM like Java.

Understanding Parentheses

New Clojure developers often struggle with parentheses. Here’s the key insight:

  • Parentheses define function calls: (function args...)
  • Everything in Clojure is an expression that returns a value
  • The first element is always the function (or special form)
1
2
3
(+ 1 2)           ; => 3 (addition)
(str "Hello" " " "World")  ; => "Hello World" (string concatenation)
(println "Hi")    ; Prints and returns nil

What Makes Clojure Special?

Even in this simple example, we see Clojure’s philosophy:

  • Simplicity: Minimal syntax, maximum expressiveness
  • Data-Oriented: Code is written as data structures
  • Functional: Functions are first-class citizens
  • Practical: Full access to Java libraries and the JVM
  • Interactive: Designed for REPL-driven development

The REPL Experience

Clojure really shines in the REPL (Read-Eval-Print Loop):

1
2
3
4
5
6
7
8
9
$ clojure
Clojure 1.12.0
user=> (println "Hello, World!")
Hello, World!
nil
user=> (+ 1 2 3)
6
user=> (str "Hello" ", " "World!")
"Hello, World!"

The REPL becomes your primary development environment, allowing you to build and test code interactively.

Next Steps

Continue exploring Clojure’s powerful features:

  • Data structures (lists, vectors, maps, sets)
  • Functions and higher-order functions
  • Immutability and persistent data structures
  • Threading macros (->, ->>)
  • Destructuring
  • Sequence operations

Clojure’s unique approach to programming emphasizes simplicity, immutability, and functional composition. While the syntax may look unusual at first, it enables powerful abstractions and a highly interactive development experience.

Welcome to the world of Clojure!

Running Today

All examples can be run using Docker:

docker pull clojure:latest
Last updated: