A pure, functional programming language inspired most by Haskell, but a bit by TypeScript.
Notable features and differences from Haskell:
- Complement types, as the (¬) function. For example:
data Errors = NotProvided + NotInteger + NotInRange
replaceLeft = f. match
(Left e) = f e
right = right
defaultToZero: ∀e. Either e Int -> Either (e & ¬NotProvided) Int
defaultToZero = replaceLeft $ match
NotProvided = Right 0
left = left
From this function and the intersection (&), the type checker is sound and axiomatic.
- Subtyping:
getRight: ∀a. Either ⊥ a -> a
getRight = match
Left e = e // Since `e` is ⊥, it is compatible with `a`
Right a = a
- Expression oriented and point-free. No special syntax in declarations. Anonymous function expressions are focused, with concise syntax for functions as well as for pattern matching:
id = x. x
type id = x. x
S = x y z. x z $ y z
type S = x y z. x z $ y z
mapMaybe = f. match
(Some x) = Some $ f x
(None) = None
- ECMAScript-like module system.
Notable features kept from Haskell:
- Lazy evaluation
- Typeclassing
- Curried by default
Some changes from Haskell:
- Emphasis on pipe operator
|
(type∀a b. a -> (a -> b) -> b
) - List types are
List a
instead of[a]
- Do notation dropped
For example, Maybe
's constructors are Some
and None
. I like Maybe
more than
Option
since it is more distinctive (more searchable, filters down autosuggest more).
I like Some
and None
and I dislike Just
and Nothing
.
Add structurally typed records inspired by TypeScript.
- Syntax
person = {
name = 'Alex Generic'
birthdate = Date 1821 4 20
customerStatus = {
joined = Date 2024 02 10
loyaltyPoints = 140
balance = 12310
}
}
- Reading and updating
The value-level &
operator can be used to combine the fields of two records
into one. Right side values are preferred over left side values.
An update
function can be derived, which takes a record with the same fields
but with each property as a function.
ageWhenJoined = person.customerStatus.joined - person.birthdate
withNewAge = person & {
name = "Alex Generic I"
birthdate = person.birthdate + 1
customerStatus = person.customerStatus & {
loyaltyPoints = person.customerStatus.loyaltyPoints + 30
}
}
withNewAgeUpdate = person | update {
name = K $ "Alex Generic I"
birthdate = (+1)
customerStatus = update {
loyaltyPoints = (+30)
}
}
- Typing
type Person = {
name: String
birthdate: Date
customerStatus: {
joined: Date
loyaltyPoints: Int
}
}
- Destructuring
type Quadratic = { a: Double, b: Double, c: Double }
y: Quadratic -> Double -> Double
y = { a, b, c } x. a * x ** 2 + b * x + c
Time complexity for property access is currently undefined.
- Recommended practice for orphan instances
- Optional fields in records
- Type union operator.
|
is taken for the pipe function, and union is not divisible as+
would imply.
- Algebraic effects