• Lisp for JS developers part 1 - fundamentals [JS, Lisp]
  • Lisp for JS developers part 2 - built-in functions [JS, Lisp]
  • Lisp for JS developers part 3 - data structures [JS, Lisp]
  • Lisp for JS developers part 4 - macros [JS, Lisp]
  • Lisp for JS developers part 5 - recursion [JS, Lisp]
  • Lisp for JS developers part 6 - AoC puzzle [JS, Lisp]
  • Introduction

    We already know how to define functions using basic types like string, boolean, or nil in Lisp. The language’s syntax is very different from other programming languages, but commonly used building blocks like variables, conditions, and loops are the same. One of the main features of functional programming is treating functions as values. We can pass them as arguments to the function or return them from the function. Functions that do that are also called “higher order functions”, and in this part of the series, we will learn a few such functions. But first, let’s start with the primitive built-in functions.

    Built-in functions

    In a “typical” programming language like JavaScript, we think in terms of built-in operators like +, -, >, ==, &&, || and existing functions like parseInt, console.log, JSON.parse, Math.max included in the standard library. In Lisp there is no difference between keywords, operators, and functions. They are all used in exactly the same way.

    Below you can find the list of standard builtin Clojure specific functions also implemented in JavaScript grouped into the sample categories like:

    • predicates nil?, string?, ..
    • arithmetic and logic operators +, *, …
    • math functions inc, dec, …
    • functions working with functions identity, constantly, …
    (nil? nil) ;; => true
    (string? "") ;; => true
    (boolean? true) ;; => true
    (int? 1) ;; => true
    (fn? +) ;; => true
    (vector? [1 2 3]) ;; => true
    
    (+ 1 2 3) ;; => 6
    (* 1 2 3) ;; => 6
    (< 1 2) ;; => true
    
    (inc 10) ;; => 11
    (dec 10) ;; => 9
    (mod 10 3) ;; => 1
    (abs -10) ;; => 10
    (max 5 10 15) ;; => 15
    
    (zero? 0) ;; => true
    (pos? 1) ;; => true
    (even? 10) ;; => true
    (odd? 11) ;; => true
    
    (identity 10) ;; => 10
    (identity "mama") ;; => "mama"
    
    ((constantly 666) 1) ;; => 666
    ((constantly 666) 1 2 3) ;; => 666
    
    ((complement empty?) [])   ;; => false
    
    (and (> 2 1) (string/ends-with? "tata" "ta") false) ;; => false
    (or (> 2 1) (string/ends-with? "tata" "ta") false) ;; => true
    
    ;; falshy - only false oraz nil
    (and "" 0) ;; => 0
    (and "" 0 false) ;; => false
    (and "" 0 nil) ;; => nil
    
    (or "" 0) ;; => ""
    
    var nilp = (x) => typeof x === "undefined" || x === null;
    var stringp = (x) => typeof x === "string";
    var booleanp = (x) => typeof x === "boolean";
    var numberp = (x) => typeof x === "number";
    var functionp = (x) => typeof x === "function";
    
    var plus = (...args) => args.reduce((p, c) => p + c, 0);
    var minus = (...args) =>
      args.length === 1 ? -args[0] : args.reduce((p, c) => p - c);
    var multiply = (...args) => args.reduce((p, c) => p * c, 1);
    var mod = (...args) => args.reduce((p, c) => p * c, 1);
    var inc = (x) => x + 1;
    var dec = (x) => x - 1;
    var mod = (x, div) => x % div;
    var abs = (x) => Math.abs(x);
    var max = (...xs) => Math.max(...xs);
    var min = (...xs) => Math.min(...xs);
    var evenp = (x) => x % 2 === 0;
    var oddp = (x) => x % 2 === 1;
    var zerop = (x) => x === 0;
    var posp = (x) => x > 0;
    var str = (...args) => args.join("");
    
    var identity = (x) => x;
    var constantly = (x) => () => x;
    var complement =
      (f) =>
      (...args) =>
        !f(...args);
    
    2 > 1 && "tata".endsWith("ta") && false; // => false
    2 > 1 || "tata".endsWith("ta") || false; // => true
    
    // ... in JS "" and 0 are also falsy
    "" && 0; // => ""
    "" && 0 && false; // => ""
    "" && 0 && null; // => ""
    
    "" || 0; // => 0
    

    Unlike in most programming languages, in Lisp, characters ? or - can be used as part of identifiers, variable or function names. There is also a naming convention for predicates (functions returning boolean values) with ? at the end, for instance (nil? ..) or (even? ...).

    Lisp uses nil values, the same as null in other languages. But there is also an additional concept called “falsy and truthy values”, which I have encountered only in JavaScript. Boolean values are mostly used inside conditions, for instance in if or while statements. The idea behind “falsy and truthy values” is that any expression in the language can be treated as a condition, it can always be converted into a boolean type. For instance, in JavaScript values like false, null, undefined, 0, "" are treated as “true”, all other expressions are “false”. That’s why we often find code like var city = (person && person.address && person.address.city) || "". It means “define a new variable city with value of person.address.city, but set empty string "" only if person or person.address or person.address.city don’t exist. In Clojure dialect of List “falsy and truthy values” work similar to JavaScript, but there are some small differences. According to the documentation: “ In Clojure, all values are logically true or false. The only “false” values are false and nil - all other values are logically true”.

    The last interesting detail is that many of the functions above are variadic. In many cases passing any number of arguments is quite convenient, for instance the conditions can be written like this (and ... (or ... ... ...) ...), or the arithmetic operations like this (+ 5 10 15), (min 5 10 15). The same function can be called with many argument values and one value representing the collection of items. We can calculate the sum of all numbers stored in the variable my-numbers by calling the helper function (apply + my-numbers).

    ‘apply’ function

    The apply function takes two arguments: a function and a collection of values. It calls the function passing values as arguments and returns the result.

    (apply add [1 2]) ;; => 3
    (apply * [2 3]) ;; => 6
    
    add.apply(null, [1, 2]);
    

    The JavaScript function is a regular object containing members like properties or methods. Method apply works almost the same as the Clojure apply function presented above. The difference is an additional argument null. In the object-oriented programming style (OOP), a method is just a function called in the context of some additional object; for instance, firstName.substring(1) is just a function substring of type string. In functional or procedural programming, we pass all data as function arguments, like substring(firstName, 1). Both JavaScript and Lisp treat functions as values. We can create a variable referencing a method const substr = firstName.substring and execute it later, execution of substr.apply("JavaScript", [1]) returns "avaScrip". The first argument of the apply function represents “this” object, the substring function was called in the context of the "JavaScript" value instead of the firstName variable.

    ‘partial’ function

    partial is another builtin function working with function values. The term “partial function application” in functional languages means “calling” a function without passing all argument values. In such a case, the function’s body can not be executed, instead a new function is created. All passed arguments are bound and the returned function expects only the missing arguments. Let’s say we have add function that adds two numbers, we can easily create a new function increment that increments by one the passed argument.

    (def increment
      (partial add 1))
    (increment 10) ;; => 11
    ((partial add 1) 10) ;; => 11
    
    var inc = add.bind(null, 1);
    inc(10); // => 11
    add.bind(null, 1)(10); // => 11
    

    Analogously to the apply function, a JavaScript object representing the function contains a method bind.

    ‘comp’ function (function composition)

    The next comp function implements the math term function composition. Let’s say we have an increment function and a str function that converts any number into a string. Now we would like to create a new function taking a number and returning a string working like this arg => str(increment(increment(arg))). A new composed function increments the number by two and converts it to a string.

    (def increment-twice-then-to-string
      (comp str increment increment))
    
    (increment-twice-then-to-string 10) ;; => "12"
    
    var comp =
      (...funcs) =>
      (arg) =>
        funcs.reduceRight((a, f) => f(a), arg);
    
    var incrementTwiceThenToString = comp(str, increment, increment);
    incrementTwiceThenToString(10); // => "12"
    

    This time there is no built-in function in JavaScript, but such a function can be easily implemented using the reduceRight array method. Many programming languages provide built-in functions or operators supporting function composition. For instance, in Haskell language . operator is used and that corresponds to the math dot notation. Our previous example would look like this str . increment . increment in Haskell. The order of functions seems unnatural, because it tries to simulate the math notation.

    Summary

    In this article, we have implemented some basic built-in Clojure functions and operators in JavaScript. Next, we will discuss data structures like immutable linked lists and maps.