Skip to content

peat-lang/peat

Repository files navigation

Meet Peat

Peat is a typed functional programming language. Here’s an example:

(Click here](https://peat-lang.fly.dev/) for a version of the example in the playground, with syntax highlighting

import core/http
import core/http/client
import core/error { Ok, Err }
import core/string

// Look at the inferred return type: the compiler knows
// this function makes HTTP requests and can fail
// (without any annotations from you)
fn weather_in(city) {
    http.get("https://wttr.in/" ++ city ++ "?format=3")
    |> http.send
    |> http.body_text
}

// This function is pure: just data in, data out.
fn beach_verdict(forecast) {
    if string.contains(forecast, "☀") {
        "Grab your towel!"
    } else if string.contains(forecast, "🌧") {
        "Stay in. Write some Peat instead."
    } else {
        "Check the window, honestly."
    }
}

@entrypoint
fn main() {
    // provide an effect handler for HTTP requests
    with client.http_client;

    let result = error.try {
      weather_in("San Francisco")
    };

    match result {
        Ok(forecast) => beach_verdict(forecast),
        Err(_) => "Couldn't check. Beach at your own risk.",
    }
}

Language Overview

Peat is a pure functional programming language with a type-and-effect system and typed effect handlers.

It is intended to be useful for real applications, while also being interesting as a project exploring programming language design and compiler implementation.

The compiler primarily targets JavaScript, for two reasons:

  1. Web applications are my primary domain, and JavaScript is still the best compiler target for interactive web applications.
  2. JavaScript includes several features (especially garbage collection and generators) that make it straightforward to build a language like this on top of an existing VM.

However, the language is built to include a relatively small number of built-in/intrinsic data types and functions, and to have most of the core functionality built in Peat itself. This has also allowed for a native backend (via Cranelift) that compiles Peat to machine code.

What’s the State of Things?

This projects exists somewhere between “real proof of concept” and “useable,” and somewhere far short of “production ready.”

It is much more than a toy language; it has things like a real module system, a core library, a limited language server, and a web framework you can build to use frontend applications. It’s missing lots of things you’d ordinarily want to use in a language, like a package manager. And it’s very much a work in progress: there are plenty of bugs, known and unknown, and a handful of language features still in progress.

Issues are not open at this time. I want to share this project with the world because I find it interesting. At the moment, I’m not willing to take on the overhead of ordinary open source maintenance for it (receiving bug reports, offering help via discussions, answering many questions, etc.) If you’re interested, feel free to reach out—at the moment, I just want to set the expectation that this is a read-only repository.

Goals and Values

These goals and values are the principles that have guided the design of the language and compiler.

  • Practicality: Explore how algebraic effects can be used to model the things needed for actual applications
  • Minimalism: Model a wide set of programming language features with the smallest possible set of core language concepts and constructs
  • Simplicity: Writing idiomatic Peat code should mostly be a matter of writing types and pure functions, taking plain data of one type and transforming it into pure data of another type. There should be a strong separation of concerns, with independent concepts clearly separated into layers of distinct functionality. (For example, a Peat framework for interactive applications should not require wrapping all data in a special wrapper type.)
  • Flexibility: Accept the widest possible variety of incomplete programs during the development process
    • Type annotations are allowed anywhere (and probably encouraged everywhere!) but required nowhere, and can be inferred by the compiler (and inserted by the language server)
    • Programs with compiler errors can still go through code generation and run; they will emit runtime errors when they hit compile errors
  • Openness and Extensibility: The core library, web framework, etc. are written entirely in Peat code and have no special privileges that other Peat code does not have. The compiler provides a few primitive data types and a few intrinsics. Any user code can use intrinsics (although uses nicer wrappers is sasumed), create extern handlers, etc.
  • Composability: The core library is built out of a number of separate, composable libraries. The goal is always to "unbundle" into libraries rather than "bundling" them into frameworks. For example, when building a web framework, we want to separate the state management, DOM renderer, routing/URL parsing, etc. into a set of separate libraries that consist primarily of pure functions on data and secondarily of the necessary effect handlers.
  • Reliability: A sound type-and-effect system makes it possible to write programs that cannot fail at runtime. It's a goal of this language for an unrecoverable runtime error to mean there's a bug in the compiler.
  • Fast Compilation: Enable a very fast feedback loop between the programmer and the compiler
    • Single-file modules as the basic unit of compilation.
    • Directed acyclic graph of module dependencies.
    • Parallel compiler frontend.
    • Simple, unification-based Hindley-Milner
  • Runtime Performance: Pure functional languages are not necessarily fast at runtime. One of the goals of Peat is to explore the ways in which we can use purity to our advantage to achieve runtime performance that is on par with imperative approaches to the same problems.
    • Implementation of multiple optimization passes in the compiler.
    • Use of function memoization in ways enabled by purity
    • Building on immutable data structures and function memoization to do incremental computations in ways that are not necessarily visible to the user

Non-Goals

These non-goals are the things that will not guide the design of the language and compiler. To say that they are “non-goals” doesn't mean I'm opposed to them; it just means they are not accepted as valid arguments for a reason to make one choice rather than another.

  • Self-hosting compiler: Rust is an excellent language for writing compilers. Even with a native backend (which doesn't exist), rewriting in Peat would simply mean a slower compiler. I am more interested in continuing to work on language features and the core libray.
  • Adoption: This is not an anti-goal, but arguments along the lines of “more people would use this if you...” are explicitly not considered.
  • Readable compiler output: Given that Peat compiles to JavaScript, emitting readable and idiomatic code is good, all else being equal. But given the level of compiler optimizations the language enables, the code that’s generated will often not look much like idiomatic JavaScript, and that’s okay.

Why the name “Peat”?

“Peat” is a fun and inoffensive one-syllable word that isn’t already the name of a programming language or a .peat file extension—at least to the best of my knowledge. It brings me back to the smell of low tide on the beach I grew up on as a child, where there was peat under the sand.

You can also build your own acronym out of whatever Peat-related keywords you’d like!

  • P: practical, programming, Peat
  • e: effects
  • a: and, algebraic
  • t: types

So if you’d like, it can be “Practical Effects And Types” or “Programming with Effects (Algebraic), Typed” or “Peat is Effectively A Treasure” or whatever else you can imagine.

About

A practical programming language exploring type-and-effect systems.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors