Functional
Functions are not everything, but...
Higher-order functions, algebraic data, and list combinators sit naturally in Par.
let answer = Int.Range(1, 100)
->List.Filter(box [i] i->Int.Mod(2) == 0)
->List.Map(box [i] i * i)
->List.Sum An experimental programming language bringing the expressive power of linear logic into practice.
Sponsoring the project helps keep Par moving from experiment toward a language you can build with.
module Playground
import {
@core/Int
@core/Nat
}
def Describe = [n: Int] if {
n < 0 => "Negative",
n == 0 => "Zero",
0 < n < 100 => "Small",
else => `Incomprehensible (#{n})`,
}
dec Factorial : [Nat] Nat
def Factorial = [n]
Nat.Range(1, n + 1).begin.case {
.end! => 1,
.item(x) xs => x * xs.loop,
}
dec Fibonacci : iterative choice {
.next => (Nat) self,
.close => !,
}
def Fibonacci = do {
let a = 0
let b = 1
} in begin case {
.next => do {
let (a, b)! = (b, a + b)!
} in (a) loop,
.close => !,
} Totality
Par rules out broad classes of errors before the program even runs: no runtime panics, no deadlocks, and no accidental infinite loops.
begin and loop. def Main =
let rootPath = Os.Path(".").append("Downloads") in
YieldDownloadRequests("127.0.0.1:3000", rootPath)
->List.Map(box DownloadFile)
->FanIn
->ShowDownloadProgress(rootPath) Automatic Concurrency
Blocking is local and induced by data dependencies. In Par, even ordinary-looking structures like lists can carry asynchronous work as their elements become available.
One Foundation
Par is Curry-Howard isomorphic to classical linear logic. At its core it is a process calculus: everything is a channel, and every operation is communication. Even lists and maps are communication channels. With syntax sugar, familiar paradigms emerge naturally as sub-languages of this single foundation.
Functional
Higher-order functions, algebraic data, and list combinators sit naturally in Par.
let answer = Int.Range(1, 100)
->List.Filter(box [i] i->Int.Mod(2) == 0)
->List.Map(box [i] i * i)
->List.Sum Object-Oriented
Choice and iterative types give Par an object-like style where methods are branches of a communication protocol.
let builder = String.Builder
builder.add("Hello")
builder.add(", ")
builder.add("world!")
let answer = builder.build Process Syntax
Par is ultimately a process language. A chan expression lets a value be constructed by talking to its consumer from the other side.
// = *(1, 2, 3)
def Numbers: List<Int> = chan yield {
yield.item(1)
yield.item(2)
yield.item(3)
yield.end!
} let map = Map.New(type String, type Int)
// Even a map has a protocol.
// Calling `.entry` advances it.
map.entry("A")[default(0) count]
// The entry "A" is activated. Now we must call
// - `.put` to insert a value, or
// - `.delete` to remove the entry.
map.put(count + 1)
// Only now can we call `.entry` again. Session Types
All values in Par are communication channels. For example, a map is not just a passive container; it has a protocol, and each operation advances that protocol.
When you call .entry, the map moves into the part of the
protocol for resolving that key. The type then guides what must happen
next before the map is available as a map again.
Explore Par
Par is named after the linear-logic connective ⅋, pronounced "par". It is an attempt to bring the expressive power of classical linear logic, session types, and process calculi into a practical language.
It is not really possible to make this paradigm feel completely familiar. Take your time with it. If the direction speaks to you, stars, feedback, discussion, and sponsorship all help.