The
Clojure
Workshop

Built by a team of experts to help you unlock your next promotion, reboot your career, or kick off your latest side project.
Cover for The Clojure Workshop

Get Started Today

You'll be up and running with Clojure programming in no time at all.

  • Free

    FreeThe Clojure Workshop

    Unlock one year of full, unlimited access and get started right away!
    Learn for Free

Engineered for Success

Nobody likes going through hundreds of pages of dry theory, or struggling with uninteresting examples that don’t compile. We've got you covered. Any time, any device.

  • Learn by doing real-world development, supported by detailed step-by-step examples, screencasts and knowledge checks.

  • Become a verified practitioner, building your credentials by completing exercises, activities and assessment checks.

  • Manage your learning based on your personal schedule, with content structured to easily let you pause and progress at will.

Learn By Doing

You already know you want to learn Clojure, and the best way to learn Clojure is to learn by doing.

The Clojure Workshop focuses on building up your practical skills to write clean, expressive code with a language that is great for applications where concurrency and interoperability with the JVM are a priority.

On Your Terms

Build up and reinforce key skills in a way that feels rewarding.

You won't have to sit through any unnecessary theory. If you're short on time you can jump into a single exercise each day or spend an entire weekend learning about Clojure web development with Ring.

An Ideal Start

Fast-paced and direct, The Clojure Workshop is the ideal companion for newcomers.

You'll build and iterate on your code like a software developer, learning along the way. This process means that you'll find that your new skills stick, embedded as best practice. A solid foundation for the years ahead.

Begin Your Journey

A simple, straightforward and pain-free way to learn Clojure.

  • Free

    FreeThe Clojure Workshop

    Unlock one year of full, unlimited access and get started right away!
    Learn for Free

Everything You Need

Every Workshop includes access to dedicated support, course discussions and a wider learning community. Ask questions, share answers and work with the community to expand your learning.

  • Engage and participate in live user discussions, baked right into your course from start to finish. Share, learn and grow together.

  • Get live updates and interact directly with the product development, editorial and authoring teams across the Packt network.

  • Create, showcase and share your own learning outcomes and motivational stories across the entire workshop community.

Get Build-Ready

Every Workshop includes a whole host of features that work together to help you get the job done. You’ll be ready to tackle real-world development in no time.
  • Hack Your Brain

    We've applied the latest pedagogical techniques to deliver a truly multimodal experience. It'll keep you engaged and make the learning stick. It's science!

  • Build Real Things

    Nobody likes wasting their time. We cut right to the action and get you building real skills that real, working developers value. The perfect approach for a career move.

  • Learn From Experts

    We've paired technical experts with top editorial talent. They've worked hard to deliver you the maximum impact for each minute you spend learning. It's our secret sauce.

  • Verify Your Credentials

    You can become a verified practitioner. Complete the course to get a certificate. It's perfect for sharing on social media. Hello LinkedIn!

  • Receive Free Updates

    Technology keeps changing, and so do we. We keep versions updated independently, so you'll always have access. No more worrying about third-party release cycles.

  • Access Anywhere

    All you need is an internet connection. We've built every course so that it works on desktop and mobile, giving you options that fit within your schedule.

What's Inside

From A to Z, we've got you covered!

  • Workshop Onboarding

    • Welcome to The Clojure Workshop
    • Installation and Setup
    • Credits
  • 1. Hello REPL!

    • Overview
    • Exercise 1.01: Your First Dance
    • Exercise 1.01: Your First Dance
    • Exercise 1.02: Getting around in the REPL
    • Exercise 1.02: Getting around in the REPL
    • Activity 1.01: Performing Basic Operations
    • Evaluation of Clojure Code
    • Exercise 1.03: Working with if, do, and when
    • Exercise 1.03: Working with if, do, and when
    • Exercise 1.04: Using def and let
    • Exercise 1.04: Using def and let
    • Exercise 1.05: Creating Simple Functions with fn and defn
    • Exercise 1.05: Creating Simple Functions with fn and defn
    • Activity 1.02: Predicting the Atmospheric Carbon Dioxide Level
    • Exercise 1.06: The Truth Is Simple
    • Exercise 1.06: The Truth Is Simple
    • Exercise 1.07: Comparing Values
    • Exercise 1.07: Comparing Values
    • Activity 1.03: The meditate Function v2.0
    • Summary
  • 2. Data Types and Immutability

    • Overview
    • Simple Data Types
    • Exercise 2.01: The Obfuscation Machine
    • Exercise 2.01: The Obfuscation Machine
    • Booleans
    • Collections
    • Exercise 2.02: Using Maps
    • Exercise 2.02: Using Maps
    • Exercise 2.03: Using Sets
    • Exercise 2.03: Using Sets
    • Exercise 2.04: Using Vectors
    • Exercise 2.04: Using Vectors
    • Exercise 2.05: Using Lists
    • Exercise 2.05: Using Lists
    • Collection and Sequence Abstractions
    • Exercise 2.06: Working with Nested Data Structures
    • Exercise 2.06: Working with Nested Data Structures
    • Activity 2.01: Creating a Simple In-Memory Database
    • Summary
  • 3. Functions in Depth

    • Overview
    • Destructuring
    • Exercise 3.01: Parsing Fly Vector's Data with Sequential Destructuring
    • Exercise 3.01: Parsing Fly Vector's Data with Sequential Destructuring
    • Exercise 3.02: Parsing MapJet Data with Associative Destructuring
    • Exercise 3.02: Parsing MapJet Data with Associative Destructuring
    • Advanced Call Signatures
    • Exercise 3.03: Multi-arity and Destructuring with Parenthmazes
    • Exercise 3.03: Multi-arity and Destructuring with Parenthmazes
    • Higher-Order Programming
    • Exercise 3.04: High-Order Functions with Parenthmazes
    • Exercise 3.04: High-Order Functions with Parenthmazes
    • Multimethods
    • Exercise 3.05: Using Multimethods
    • Exercise 3.05: Using Multimethods
    • Activity 3.01: Building a Distance and Cost Calculator
    • Summary
    • Survey 1
  • 4. Mapping and Filtering

    • Overview
    • Exercise 4.01: Working with map
    • Exercise 4.01: Working with map
    • Exercise 4.02: Getting Started with filter
    • Exercise 4.02: Getting Started with filter
    • Exercise 4.03: Partitioning a Sequence with take-while and drop-while
    • Exercise 4.03: Partitioning a Sequence with take-while and drop-while
    • Using map and filter Together
    • Exercise 4.04: Watching Lazy Evaluation
    • Exercise 4.04: Watching Lazy Evaluation
    • Exercise 4.05: Creating Our Own Lazy Sequence
    • Exercise 4.05: Creating Our Own Lazy Sequence
    • Exercise 4.06: Extracting Data from a List of Maps
    • Exercise 4.06: Extracting Data from a List of Maps
    • Exercise 4.07: Using comp and a Set to Filter on a Keyword
    • Exercise 4.07: Using comp and a Set to Filter on a Keyword
    • Returning a List Longer than the Input with mapcat
    • Exercise 4.08: Identifying Weather Trends
    • Exercise 4.08: Identifying Weather Trends
    • Exercise 4.09: Finding the Average Weather Temperature
    • Exercise 4.09: Finding the Average Weather Temperature
    • Activity 4.01: Using map and filter to Report Summary Information
    • Exercise 4.10: Importing Data from a CSV File
    • Exercise 4.10: Importing Data from a CSV File
    • Exercise 4.11: Avoiding Lazy Evaluation Traps with Files
    • Exercise 4.11: Avoiding Lazy Evaluation Traps with Files
    • Exercise 4.12: Parsing CSV with semantic-csv
    • Exercise 4.12: Parsing CSV with semantic-csv
    • Exercise 4.13: Querying the Data with filter
    • Exercise 4.13: Querying the Data with filter
    • Exercise 4.14: A Dedicated Query Function
    • Exercise 4.14: A Dedicated Query Function
    • Exercise 4.15: Using filter to Find a Tennis Rivalry
    • Exercise 4.15: Using filter to Find a Tennis Rivalry
    • Activity 4.02: Arbitrary Tennis Rivalries
    • Summary
  • 5. Many to One: Reducing

    • Overview
    • The Basics of reduce
    • Exercise 5.01: Finding the Day with the Maximum Temperature
    • Exercise 5.01: Finding the Day with the Maximum Temperature
    • Initializing reduce
    • Exercise 5.02: Measuring Elevation Differences on Slopes
    • Exercise 5.02: Measuring Elevation Differences on Slopes
    • Exercise 5.03: Winning and Losing Streaks
    • Exercise 5.03: Winning and Losing Streaks
    • Exercise 5.04: Creating a Lookup Table with zipmap
    • Exercise 5.04: Creating a Lookup Table with zipmap
    • Maps to Sequences, and Back Again
    • Exercise 5.05: Quick Summary Statistics with group-by
    • Exercise 5.05: Quick Summary Statistics with group-by
    • Exercise 5.06: Complex Accumulation with reduce
    • Exercise 5.06: Complex Accumulation with reduce
    • Exercise 5.07: Calculating Probabilities for a Single Match
    • Exercise 5.07: Calculating Probabilities for a Single Match
    • Exercise 5.08: Updating Player Ratings
    • Exercise 5.08: Updating Player Ratings
    • Activity 5.01: Calculating Elo Ratings for Tennis
    • Summary
  • 6. Recursion and Looping

    • Overview
    • Clojure's Most Procedural Loop: doseq
    • Exercise 6.01: An Endless Stream of Groceries
    • Exercise 6.01: An Endless Stream of Groceries
    • Exercise 6.02: Partitioning Grocery Bags
    • Exercise 6.02: Partitioning Grocery Bags
    • Exercise 6.03: Large-Scale Grocery Partitioning with recur
    • Exercise 6.03: Large-Scale Grocery Partitioning with recur
    • Exercise 6.04: Groceries with loop
    • Exercise 6.04: Groceries with loop
    • Tail Recursion
    • Exercise 6.05: Europe by Train
    • Exercise 6.05: Europe by Train
    • Exercise 6.06: The Search Function
    • Exercise 6.06: The Search Function
    • Exercise 6.07: Calculating the Costs of the Routes
    • Exercise 6.07: Calculating the Costs of the Routes
    • A Brief Introduction to HTML
    • Activity 6.01: Generating HTML from Clojure Vectors
    • Summary
  • 7. Recursion II: Lazy Sequences

    • Overview
    • A Simple Lazy Sequence
    • Exercise 7.01: Finding Inflection Points
    • Exercise 7.01: Finding Inflection Points
    • Exercise 7.02: Calculating a Running Average
    • Exercise 7.02: Calculating a Running Average
    • Lazy Consumption of Data
    • Exercise 7.03: A Tennis History Tree
    • Exercise 7.03: A Tennis History Tree
    • Exercise 7.04: A Custom take Function
    • Exercise 7.04: A Custom take Function
    • Exercise 7.05: Formatting the Matches
    • Exercise 7.05: Formatting the Matches
    • Activity 7.01: Historical, Player-Centric Elo
    • Summary
  • 8. Namespaces, Libraries and Leiningen

    • Overview
    • Exercise 8.01: Investigating Namespaces Started by Default in REPL
    • Exercise 8.01: Investigating Namespaces Started by Default in REPL
    • Exercise 8.02: Navigating Namespaces
    • Exercise 8.02: Navigating Namespaces
    • Exercise 8.03: Using the refer Function to Import a Namespace
    • Exercise 8.03: Using the refer Function to Import a Namespace
    • Exercise 8.04: Using the :only Keyword
    • Exercise 8.04: Using the :only Keyword
    • Exercise 8.05: Using the :exclude Keyword
    • Exercise 8.05: Using the :exclude Keyword
    • Exercise 8.06: Using the :rename Keyword
    • Exercise 8.06: Using the :rename Keyword
    • Exercise 8.07: Importing Clojure Functions with require and use
    • Exercise 8.07: Importing Clojure Functions with require and use
    • Activity 8.01: Altering the Users List in an Application
    • When You Want use versus When You Want require
    • Exercise 8.08: Creating a Leiningen Project
    • Exercise 8.08: Creating a Leiningen Project
    • Investigating project.clj
    • Exercise 8.09: Executing the Application on the Command Line
    • Exercise 8.09: Executing the Application on the Command Line
    • Exercise 8.10: Executing application on the command line with arguments
    • Exercise 8.10: Executing application on the command line with arguments
    • Activity 8.02: Summing Up Numbers
    • Exercise 8.11: Using an External Library in a Leiningen Project
    • Exercise 8.11: Using an External Library in a Leiningen Project
    • Exercise 8.12: Creating a Jar File
    • Exercise 8.12: Creating a Jar File
    • Exercise 8.13: Adding Leiningen Profiles to a Project
    • Exercise 8.13: Adding Leiningen Profiles to a Project
    • Exercise 8.14: Using User-Wide Profiles
    • Exercise 8.14: Using User-Wide Profiles
    • Useful Clojure Libraries
    • Activity 8.03: Building a Format-Converting Application
    • Summary
    • Survey 2
  • 9. Host Platform Interoperability with Java and JavaScript

    • Overview
    • Exercise 9.01: Importing a Single Java Class in Clojure
    • Exercise 9.01: Importing a Single Java Class in Clojure
    • Exercise 9.02: Importing Multiple Java Classes in Clojure
    • Exercise 9.02: Importing Multiple Java Classes in Clojure
    • Exercise 9.03: Macros That Help Us Use Java in Clojure
    • Exercise 9.03: Macros That Help Us Use Java in Clojure
    • Exercise 9.04: Coffee-Ordering Application – Displaying a Menu
    • Exercise 9.04: Coffee-Ordering Application – Displaying a Menu
    • Exercise 9.05: Coffee-Ordering Application – Saving and Loading Orders
    • Exercise 9.05: Coffee-Ordering Application – Saving and Loading Orders
    • Exercise 9.06: Java Data Types
    • Exercise 9.06: Java Data Types
    • Activity 9.01: Book-Ordering Application
    • Using JavaScript in ClojureScript
    • Exercise 9.07: Working with JavaScript Data Types
    • Exercise 9.07: Working with JavaScript Data Types
    • Exercise 9.08: Investigating Figwheel and Rum
    • Exercise 9.08: Investigating Figwheel and Rum
    • Figwheel Template
    • Exercise 9.09: JavaScript Interoperability with Drag and Drop
    • Exercise 9.09: JavaScript Interoperability with Drag and Drop
    • Exercise 9.10: Handling Errors and Exceptions in Clojure
    • Exercise 9.10: Handling Errors and Exceptions in Clojure
    • Exercise 9.11: Handling Errors in ClojureScript
    • Exercise 9.11: Handling Errors in ClojureScript
    • Activity 9.02: Creating a Support Desk
    • Summary
  • 10. Testing

    • Overview
    • Why Testing Is Important
    • Exercise 10.01: Unit Testing with the clojure.test Library
    • Exercise 10.01: Unit Testing with the clojure.test Library
    • Exercise 10.02: Testing the Coffee Application with Expectations
    • Exercise 10.02: Testing the Coffee Application with Expectations
    • Exercise 10.03: Testing the Coffee Application with Midje
    • Exercise 10.03: Testing the Coffee Application with Midje
    • Exercise 10.04: Using Property-Based Testing in the Coffee-Ordering Application
    • Exercise 10.04: Using Property-Based Testing in the Coffee-Ordering Application
    • Activity 10.01: Writing Tests for the Coffee-Ordering Application
    • Exercise 10.05: Setting Up Testing in ClojureScript
    • Exercise 10.05: Setting Up Testing in ClojureScript
    • Exercise 10.06: Testing ClojureScript Code
    • Exercise 10.06: Testing ClojureScript Code
    • Exercise 10.07: Tests in Figwheel Applications
    • Exercise 10.07: Tests in Figwheel Applications
    • Exercise 10.08: Testing a ClojureScript Application
    • Exercise 10.08: Testing a ClojureScript Application
    • Activity 10.02: Support Desk Application with Tests
    • Summary
  • 11. Macros

    • Overview
    • What is a Macro?
    • Exercise 11.01: The and-ors Macro
    • Exercise 11.01: The and-ors Macro
    • Exercise 11.02: An Automatic HTML Library
    • Exercise 11.02: An Automatic HTML Library
    • Exercise 11.03: Expanding the HTML Library
    • Exercise 11.03: Expanding the HTML Library
    • Macros in ClojureScript
    • Macro Hygiene
    • Exercise 11.04: Monitoring Functions
    • Exercise 11.04: Monitoring Functions
    • When to Use Manual gensyms
    • Activity 11.01: A Tennis CSV Macro
    • Interface Design
    • Summary
  • 12. Concurrency

    • Overview
    • Concurrency in General
    • Exercise 12.01: Testing Randomness
    • Exercise 12.01: Testing Randomness
    • Exercise 12.02: A Crowdsourced Spellchecker
    • Exercise 12.02: A Crowdsourced Spellchecker
    • Coordination
    • Exercise 12.03: Stock Trading
    • Exercise 12.03: Stock Trading
    • Exercise 12.04: Keeping up with the Stock Price
    • Exercise 12.04: Keeping up with the Stock Price
    • Exercise 12.05: Rock, Scissors, Paper
    • Exercise 12.05: Rock, Scissors, Paper
    • Exercise 12.06: One, Two, Three… "Rock!"
    • Exercise 12.06: One, Two, Three… "Rock!"
    • Activity 12.01: A DOM Whack-a-mole Game
    • Summary
  • 13. Database Interaction and the Application Layer

    • Overview
    • Exercise 13.01: Establishing a Database Connection
    • Exercise 13.01: Establishing a Database Connection
    • Exercise 13.02: Creating a Connection Pool
    • Exercise 13.02: Creating a Connection Pool
    • Exercise 13.03: Defining and Applying a Database Schema
    • Exercise 13.03: Defining and Applying a Database Schema
    • Managing Our Data
    • Exercise 13.04: Data Insertion
    • Exercise 13.04: Data Insertion
    • Exercise 13.05: Querying Our Database
    • Exercise 13.05: Querying Our Database
    • Exercise 13.06: Controlling Results with Custom Functions
    • Exercise 13.06: Controlling Results with Custom Functions
    • Exercise 13.07: Updating and Removing Existing Data
    • Exercise 13.07: Updating and Removing Existing Data
    • Exercise 13.08: Defining the Application Layer
    • Exercise 13.08: Defining the Application Layer
    • Activity 13.01: Persisting Historic Tennis Results and ELO Calculations
    • Summary
    • Survey 3
  • 14. HTTP with Ring

    • Overview
    • Exercise 14.01: Creating a Hello World Web Application
    • Exercise 14.01: Creating a Hello World Web Application
    • Exercise 14.02: Introducing Routing with Compojure
    • Exercise 14.02: Introducing Routing with Compojure
    • Exercise 14.03: Response Rendering with Muuntaja
    • Exercise 14.03: Response Rendering with Muuntaja
    • Exercise 14.04: Working with a request Body
    • Exercise 14.04: Working with a request Body
    • Exercise 14.05: Serving Static Files
    • Exercise 14.05: Serving Static Files
    • Exercise 14.06: Integrating with an Application Layer
    • Exercise 14.06: Integrating with an Application Layer
    • Activity 14.01: Exposing Historic Tennis Results and ELO Calculations via REST
    • Summary
  • 15. The Frontend: A ClojureScript UI

    • Overview
    • Hiccup instead of HTML
    • Exercise 15.01: Creating a Reagent Application
    • Exercise 15.01: Creating a Reagent Application
    • Exercise 15.02: Displaying an Image with Style
    • Exercise 15.02: Displaying an Image with Style
    • Exercise 15.03: A Button that Modifies Its Text
    • Exercise 15.03: A Button that Modifies Its Text
    • Exercise 15.04: Creating a Grid of Images
    • Exercise 15.04: Creating a Grid of Images
    • Exercise 15.05: Fetching Data from an HTTP Endpoint
    • Exercise 15.05: Fetching Data from an HTTP Endpoint
    • Activity 15.01: Displaying a Grid of Images from the Internet
    • Activity 15.02: Tennis Players with Ranking
    • Summary
  • Activity Solutions

    • Activity 1.01: Performing Basic Operations
    • Activity 1.01: Performing Basic Operations
    • Activity 1.02: Predicting the Atmospheric Carbon Dioxide Level
    • Activity 1.02: Predicting the Atmospheric Carbon Dioxide Level
    • Activity 1.03: The meditate Function v2.0
    • Activity 1.03: The meditate Function v2.0
    • Activity 2.01: Creating a Simple In-Memory Database
    • Activity 2.01: Creating a Simple In-Memory Database
    • Activity 3.01: Building a Distance and Cost Calculator
    • Activity 3.01: Building a Distance and Cost Calculator
    • Activity 4.01: Using map and filter to Report Summary Information
    • Activity 4.01: Using map and filter to Report Summary Information
    • Activity 4.02: Arbitrary Tennis Rivalries
    • Activity 4.02: Arbitrary Tennis Rivalries
    • Activity 5.01: Calculating Elo Ratings for Tennis
    • Activity 5.01: Calculating Elo Ratings for Tennis
    • Activity 6.01: Generating HTML from Clojure Vectors
    • Activity 6.01: Generating HTML from Clojure Vectors
    • Activity 7.01: Historical, Player-Centric Elo
    • Activity 7.01: Historical, Player-Centric Elo
    • Activity 8.01: Altering the Users List in an Application
    • Activity 8.01: Altering the Users List in an Application
    • Activity 8.02: Summing Up Numbers
    • Activity 8.02: Summing Up Numbers
    • Activity 8.03: Building a Format-Converting Application
    • Activity 8.03: Building a Format-Converting Application
    • Activity 9.01: Book-Ordering Application
    • Activity 9.01: Book-Ordering Application
    • Activity 9.02: Creating a Support Desk
    • Activity 9.02: Creating a Support Desk
    • Activity 10.01: Writing Tests for the Coffee-Ordering Application
    • Activity 10.01: Writing Tests for the Coffee-Ordering Application
    • Activity 10.02: Support Desk Application with Tests
    • Activity 10.02: Support Desk Application with Tests
    • Activity 11.01: A Tennis CSV Macro
    • Activity 11.01: A Tennis CSV Macro
    • Activity 12.01: A DOM Whack-a-mole Game
    • Activity 12.01: A DOM Whack-a-mole Game
    • Activity 13.01: Persisting Historic Tennis Results and ELO Calculations
    • Activity 13.01: Persisting Historic Tennis Results and ELO Calculations
    • Activity 14.01: Exposing Historic Tennis Results and ELO Calculations via REST
    • Activity 14.01: Exposing Historic Tennis Results and ELO Calculations via REST
    • Activity 15.01: Displaying a Grid of Images from the Internet
    • Activity 15.01: Displaying a Grid of Images from the Internet
    • Activity 15.02: Tennis Players with Ranking
    • Activity 15.02: Tennis Players with Ranking

Get Verified

Complete The Clojure Workshop to unlock your certificate.

You can unlock the certificate by completing the course. The credentials are easy to share, and are ideal for displaying on your LinkedIn profile.
A copy of a certificate for The Clojure Workshop

Take A Step Forward

There has never been a better time to start learning Clojure.

  • Free

    FreeThe Clojure Workshop

    Unlock one year of full, unlimited access and get started right away!
    Learn for Free

Already Know Clojure?

Don't worry, we've got your back with other languages and frameworks too!

Show me my options!