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 🙏

© 2024 – Pkg Stats / Ryan Hefner

lambdant

v0.6.0

Published

A Javascript dialect for modern functional programming.

Downloads

5

Readme

lambdant

A Javascript dialect for modern functional programming.

Table of Contents

Get

Globally install the cli tools:

# npm i -g lambdant

Locally install the standard library:

$ npm i stdlm

Add the following line to your .vimrc for syntax highlighting:

au BufEnter,BufNewFile,BufRead *.lm set filetype=javascript

Hello World

hello.lm

&'Hello, world!'
$ lm e hello.lm
  'Hello, world!'

Purpose

Lambdant is a Javascript dialect that...

  • is geared towards general-purpose functional programming
  • encourages purity but does not require it
  • provides easy and intuitive Javascript ffi

Ecosystem

Files

  • ./lang/grammar.g contains the Jison grammar
  • ./lang/lexer.l contains the Jison lex file
  • ./src/parser.js is the parser script, compiled by jison ./lang/grammar.g ./lang/lexer.l -o .src/parser.js
  • ./src/gen.js generates an ESTree compliant Javascript ast given a Lambdant ast
  • ./src/index.js exposes three API calls:
    • parse(LambdantSource) -> LambdantAST parses a Lambdant source string and returns a Lambdant ast
    • generate(LambdantAST) -> ESTreeAST converts a Lambdant ast into an ESTree ast
    • serialize(ESTreeAST) -> JavascriptSource generates Javascript source from an ESTree ast

Scripts

make build generates ./src/parser.js from ./lang/grammar.g and ./lang/lexer.l.
make suite evaluates each of the scripts in ./examples.

Usage

CLI

dump: dump Lambdant source, Lambdant ast, ESTree ast, and Javascript source for a Lambdant file

$ lm d file.lm

compile: transform Lambdant source file into Javascript and write it to stdout

$ lm c file.lm

eval: transform Lambdant source file into Javascript and run it in a new node process

$ lm e file.lm

eval-arg: transform Lambdant source string into Javascript and run it in a new node process

$ lm a '& Math.log10 1000'
  3

Node

import { parse, generate, serialize } from 'lambdant'
import { readFileSync as read, writeFileSync as write } from 'fs'

const source = read('script.lm', 'utf8')
const lm_ast = parse(source)
const es_ast = generate(lm_ast)
const js_source = serialize(es_ast)

write('script.js', js_source)

Note

These commands will automatically prepend an import statement for the standard library (@$ = require 'stdlm';) to each Lambdant source file. This is useful for testing and development, but not recommended for production code. To opt out, suffix the mode argument with a dash:

$ lm d- file.lm # dump file.lm without implicit prelude
$ lm c- file.lm # compile file.lm without implicit prelude
$ lm e- file.lm # evaluate file.lm without implicit prelude
$ lm a- 'code' # evaluate code without implicit prelude

Language

Note: for all examples below, assume that standard library functions have been preassigned e.g.

@{ add, sub } = require 'stdlm';
add 2 (sub 2 1) -> 3

Operator Associativity/Precedence

()
.
!
application
* !!
:
?/
&

Values

2 -> 2
'abc' -> 'abc'
() -> null
<1, 2, 3> -> [1, 2, 3]
{ a: 5, b: 6, c } -> { a: 5, b: 6, c: c }

Expressions

add

add 2 3 -> 5
console.log() // null
console.log! // (newline)

Comments

  • single comments begin with a # and end with a newline
  • multiline comments begin with a ## and end with ## or a single comment
# single comment

## begin comment
&'this code will not be reached'
# end comment

# begin comment
&'this code will be reached'
# end comment

Lambdas

add

# single lambda
[x: add 2 x] 3 -> 5

# nested lambda
[x:[y: add x y]] 2 3 -> 5

# nested lambda shorthand
[x y: add x y] 2 3 -> 5

# multivariate lambda
[x y, add x y] (2, 3) -> 5

# thunk
[:'in a thunk!']! -> in a thunk!

# noop
[:] -> (noop)

# destructuring lambda
[{ add } <a, b>: add a b] $ <1, 2> -> 3

Blocks

Every statement in a block, except for the last, must be semicolon-terminated.
If the last expression is terminated, the function will return undefined, otherwise, it will return the expression.

@write = process.stdout.write : String;
write 'This will not return: ';
write [: 42;]!;
console.log!;
write 'This will return: ';
write [: 42]!;
console.log!

// This will not return: undefined
// This will return: 42

Declaration

@some_var

Definition

add

# basic
@name = 'John';
name -> 'John'

# destructuring
@{ x } = { x: 40 };
@<y> = <2>;
add x y -> 42

Assignment

# basic
@w;
w = 5;
w -> 5

# destructuring
@a; @b;
<a, b> = <1, 2>;
add a b -> 3;

# destructuring
@obj = { a: 5 };
obj.a = 42;
obj.a -> 42

Conditionals

Conditionals take the form of test ? consequent : alternate. If you need to make multiple statements within a branch, wrap the branch in an immediately-invoked thunk. is not mod

@odd = [x: (not : is 0) (mod x 2)];
@result = odd 3 ? 'odd!' / 'even!' -> 'odd!'

Members

# native access
Date.now! -> 1481926731041

# computed access
<1, 9, 8, 4>.(2) -> 8

Javascript FFI

Constructors

Javascript new has unconventional function call semantics; its arity changes depending on the context of the expression.

new (Date) // <Date>
new (Date)() // <Date>
const now = new Date
now() // Error!

It is best to use a function with better defined arity, like create:

(create Array <5>).fill 0 -> [0, 0, 0, 0, 0]

Multivariate Functions

The standard library provides currying and uncurrying facilities up to 5-arity.
add uncurry2 curry3

uncurry2 [x y: add x y] !! <1, 2> -> 3
uncurry2 [x y: add x y] (1, 2) -> 3
curry3 Date.UTC 1982 9 1 -> 402278400000
((Array 5).fill 0).map (uncurry2 [- i: i]) -> [0, 1, 2, 3, 4]

You can also use multivariate lambda literals and spreads for multivariate calls.
sum

[x y z, sum <x, y, z>] !! <1, 2, 3> -> 6
((Array 5).fill 0).map [- i, i] -> [0, 1, 2, 3, 4]

Native Combinators

T-combinator (*)

reverse application
add

(2 * add) 1 -> 3

infix expressions
add

add 2 3 -> 5
2 *add 3 -> 5
3 *[x: add 2 x] -> 5

reverse postfix expressions
add

3 *(2 *add) -> 5

B-combinator (:)

Composes functions. add

(add 2 : add 1) 3 -> 6

P-combinator (&)

Prints and returns the argument.
This combinator has the lowest precedence -- to avoid confusion, place a space between the combinator and the expression if the expression contains a space and is not delimited.
Calls log under the hood; reassigning $ will break this functionality. add

&42 -> 42 // 42
& add 40 2 -> 42 // 42
&(add 40 2) -> 42 // 42

E-combinator (!)

Evaluates a thunk. (Calls a function with zero arguments.)
This is preferable to calling with null (()).

process.exit!

A'-combinator (!!)

Applies a sequence to a multivariate function. (Spreads an array into a function.)
Useful for Javascript FFI.

@date_args = <1982, 9, 1>;
Date.UTC !! date_args -> 402278400000
Date.UTC(1982, 9, 1) -> 402278400000

TODO

  • loops (optional, can be implemented with conditionals and recursion)
  • dedicated syntax highlighting
  • add tests