Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

func: Named Functions

func is Lykn’s primary function form. It uses keyword-labeled clauses — :args, :returns, :body — that make the function’s contract visible at a glance.

The Basics

(func add
  :args (:number a :number b)
  :returns :number
  :body (+ a b))
function add(a, b) {
  if (typeof a !== "number" || Number.isNaN(a))
    throw new TypeError(
      "add: arg 'a' expected number, got " + typeof a);

  if (typeof b !== "number" || Number.isNaN(b))
    throw new TypeError(
      "add: arg 'b' expected number, got " + typeof b);

  const result__gensym0 = a + b;
  if (typeof result__gensym0 !== "number" || Number.isNaN(result__gensym0))
    throw new TypeError(
      "add: return value expected number, got " + typeof result__gensym0);

  return result__gensym0;
}

With --strip-assertions:

function add(a, b) {
  return a + b;
}

The Clause Structure

Every func has a name, followed by keyword-labeled clauses:

:args lists the typed parameters. Every parameter requires a type keyword. :any is the explicit opt-out for untyped parameters. Bare symbols — (func add :args (a b) ...) — are a compile error.

:returns declares the return type. When present, the compiler emits a return statement on the last body expression and a type check on the returned value. Without :returns, the function is void — no return statement is emitted.

:body contains all remaining expressions. Everything after :body is the function body. Multi-expression bodies are natural — each expression becomes a statement, and the last one is returned (if :returns is present):

(func greet-and-log
  :args (:string name)
  :returns :string
  :body
  (console:log (template "Greeting " name))
  (template "Hello, " name "!"))
function greetAndLog(name) {
  // ... type checks ...
  console.log(`Greeting ${name}`);
  return `Hello, ${name}!`;
}

Void Functions

Functions without :returns emit no return statement:

(func log-message
  :args (:string msg)
  :body (console:log msg))
function logMessage(msg) {
  // ... type check ...
  console.log(msg);
}

Use :returns :void if you want to be explicit about the void return. The behaviour is the same — no return statement — but the intent is documented.

camelCase

The function name follows the standard conversion: log-message becomes logMessage, get-user-by-id becomes getUserById. You write lisp-case; the output is idiomatic JavaScript.

A Preview

In Chapter 8, we’ll see how func supports multiple clauses with different arities and types — Erlang-style dispatch on arguments — and contracts with :pre/:post for runtime validation. For now, single-clause func covers the vast majority of functions you’ll write.