8000 GitHub - hnatiukr/ts-expression at v2.0.0
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

hnatiukr/ts-expression

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TS-Expression

TypeScript constructor of symbolic expressions.

<1kB | no deps | tree-shakeable | side-effect free

Deno MIT License

This library provides a minimal yet powerful implementation of Lisp's symbolic expressions (s-expressions) for TypeScript. By starting with these fundamental building blocks, you can create immutable, composable data structures that work well with functional programming patterns. The library's simplicity makes it easy to understand and extend, while its type-safety ensures reliability in larger applications.

Installation

Deno

deno add jsr:@lambda/ts-expression

Node.js (npx)

npx jsr add @lambda/ts-expression

Bun

bunx jsr add @lambda/ts-expression

pnpm

pnpm dlx jsr add @lambda/ts-expression

Yarn

yarn dlx jsr add @lambda/ts-expression

Examples

Representing 2D Points

import { car, cdr, cons } from "@lambda/ts-expression";

type Point = typeof makePoint;

const makePoint = (x: number, y: number) => cons(x, y);
const getX = (point: Point) => car(point);
const getY = (point: Point) => cdr(point);

const getSymmetricalPoint = (point: Point) => {
  const x = getX(point);
  const y = getY(point);
  return makePoint(-x, -y);
};

const calculateDistance = (point1: Point, point2: Point) => {
  const [x1, y1] = [getX(point1), getY(point1)];
  const [x2, y2] = [getX(point2), getY(point2)];
  return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
};

const point1 = makePoint(3, 4);
const point2 = makePoint(0, 0);

getX(point1); // 3
getY(point2); // 0
getSymmetricalPoint(makePoint(1, 5)); // makePoint(-1, -5)
calculateDistance(makePoint(-2, -3), makePoint(-4, 4)); // ≈ 7.28

Building a Binary Tree

import { cons, car, cdr } from "@lambda/ts-expression";

const leaf = <T>(value: T) => cons(value, cons(null, null));

const node = <N, L, R>(value: N, left: L, right: R) => {
  return cons(value, cons(left, right));
};
8000


const tree = node(
  "root",
  node("left", leaf("left-left"), leaf("left-right")),
  node("right", leaf("right-left"), leaf("right-right")),
);

car(tree); // "root"
car(car(cdr(tree))); // "left"

File System path representation

import { cons, car, cdr } from "@lambda/ts-expression";

const node = <A, B>(a: A, b: B) => cons(a, b);

const fs_tree = node(
  "dir:root",
  node(
    node("dir:usr", node("dir:bin", node("dir:etc", "file:readme.txt"))),
    node("dir:opt", node("dir:vol", node("dir:tmp", "file:script.sh"))),
  ),
);

const cdaar = car(car(cdr(fs_tree)));
const cdadar = car(cdr(car(cdr(fs_tree))));
const cdadddr = cdr(cdr(cdr(car(cdr(fs_tree)))));
const cddar = car(cdr(cdr(fs_tree)));

Mnemonic

The general rule for c[a/d][a/d][a/d][a/d]r functions:

  • read from right to left (just like function composition)
  • a stands for car (access the first element)
  • d stands for cdr (drop the first element)

Basic Patterns

Function Equivalent Expression Meaning
(car X) (first X) First element
(cdr X) (rest X) Everything except the first element
(cadr X) (car (cdr X)) Second element
(cddr X) (cdr (cdr X)) Drops first two elements
(caddr X) (car (cdr (cdr X))) Third element
(cdddr X) (cdr (cdr (cdr X))) Drops first three elements

Two-Layer Deep Patterns

Function Equivalent Expression Meaning
(caar X) (car (car X)) First of the first
(cadr X) (car (cdr X)) Second element
(cdar X) (cdr (car X)) Rest of the first
(cddr X) (cdr (cdr X)) Drops first two elements

Three-Layer Deep Patterns

Function Equivalent Expression Meaning
(caaar X) (car (car (car X))) First of the first of the first
(caadr X) (car (car (cdr X))) First of the second
(cadar X) (car (cdr (car X))) Second of the first
(caddr X) (car (cdr (cdr X))) Third element
(cdaar X) (cdr (car (car X))) Rest of the first of the first
(cdadr X) (cdr (car (cdr X))) Rest of the second
(cddar X) (cdr (cdr (car X))) Rest of the first after dropping its first element
(cdddr X) (cdr (cdr (cdr X))) Drops first three elements

Inspirations

This library provides a TypeScript implementation of symbolic expressions (S-expressions), which are a fundamental data structure in Lisp programming languages. S-expressions originated in the 1950s with John McCarthy's work on Lisp and have since become an elegant foundation for functional programming.

The core of S-expressions is the cons cell - a simple pair that holds two values. This primitive structure can be used to build complex data structures like lists, trees, and graphs. The operations to access the parts of a cons cell are traditionally called:

  • car (Contents of Address Register) - retrieves the first/left element
  • cdr (Contents of Decrement Register) - retrieves the second/right element

These peculiar names are historical artifacts from the IBM 704 computer on which Lisp was first implemented.

License

Copyright © 2025 Roman Hnatiuk

Licensed under MIT.

0