npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

lambiguous

v1.0.1

Published

A generalized backtracking search library

Readme

lamb(iguous)

A generalized backtracking search library for Javascript. This is inspired by John McCarthy's ambiguous operator (amb). The amb operator implements a system which is capable of automatically searching for a set of values bound to variables (henceforth called ambiguous variables) for which a set of constraints is satisfied. The operator and its usage is described in Structure and Interpretation of Computer Programs (Chapter 4.3).

amb provides a really simple, declarative interface for implementing search problems. Lamb aims to provide a similar interface for such problems in Javascript.

Usage

Instantiate a new Lamb instance to begin specifying and solving problems.

let lamb = new Lamb<number>();

Notice the type annotation. This specifies the type of values in your search space. You can pass in any to search through a non-homogeneous search space. Let's implement a simple program that returns all pairs of numbers from the lists [1, 2, 3, 4, 5] and [1, 2, 3, 4, 5] such that their sum is 7.

let lamb = new Lamb<number>();

lamb.addChoice("x", [1, 2, 3, 4, 5]);
lamb.addChoice("y", [1, 2, 3, 4, 5]);
lamb.addConstraint((vars) => vars.x + vars.y == 7);

lamb.solve(1);

A few points to note here:

  • The addConstraint method takes in a callback that gets a dict mapping the problem variables to some assignment of values.
  • The solve method optionally takes a positive integer as an argument that specifies the desired number of solutions. By default, if no such argument is provided, all solutions are returned.
  • The solve method returns an array of dictionaries each representing valid assignments for the given constraints.

For a more sophisticated example, let's write a program to solve the map colouring problem (with 4 colors) for the following map taken from here.

let lamb = new Lamb<string>();

const colors = ["red", "green", "blue", "yellow"];
let adjacencyList = {
    "a": ["b", "c", "d", "f"],
    "b": ["a", "c", "d"],
    "c": ["a", "b", "d", "e"],
    "d": ["a", "b", "c", "e", "f"],
    "e": ["c", "d", "f"],
    "f": ["a", "d", "e"]
}

type Node = keyof typeof adjacencyList; // "a" | "b" | "c" | "d" | "e" | "f "
const nodes = Object.keys(adjacencyList) as Node[];

// Add the same color choices for each node in the graph
nodes.forEach(node => lamb.addChoice(node, colors));

// The only constraint we have is that each node must not share colors with its neighbours
lamb.addConstraint((colors) =>
    !nodes.some(node =>
        adjacencyList[node].some(neighbour => colors[neighbour] === colors[node])
    )
);

lamb2.solve(1);

We represent the graph as a adjacency list, and for each node, we need add the same choice of colors. The only constraint we have is that each node must not have the same colors as its neighbours.

Finally, here is a program that solves the 8 queens problem:

let lamb = new Lamb<number>();

const N = 8;
for (let i = 0; i < N; i++) {
    // only assign columns since the row assignments are implicit (i.e must be 1, 2, 3,..., 8)
    lamb.addChoice("col" + i, [...Array(N)].map((_, j) => j + 1));
}

lamb.addConstraint((positions) =>
    ![...Array(N)].some((_, i) =>
        [...Array(i)].some((_, j) => // only check columns < i
            positions["col" + i] === positions["col" + j] || // same row?
            Math.abs(i - j) === Math.abs(positions["col" + i] - positions["col" + j]) // same diagonal?
        )
    )
);

lamb.solve(1);

Hopefully these examples were helpful in conveying the utility of Lamb. It is a really tiny library so feel free to explore the source code and make a PR if you find bugs or if you have any feature requests.