Replies: 10 comments 29 replies
This comment has been hidden.
This comment has been hidden.
-
Algebraic effects seem like a nice addition to the language, in order to be explicit about side effects of a given function.
Algebraic effects generalize exceptions by allowing arbitrary computation-stopping (potentially resuming) functions to be called. Effects are also present in the type system, disallowing not handling some effects when required, or being effect-polymorphic. Here is how the language can be extended for effects:
Foreign imported C functions cannot be made effectful, in order not to expose the internal effect handler API. |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
There are multiple ways to handle ad-hoc polymorphism (re-defining a given function with different types):
The retained option is number 2, adding type classes and implementations.
|
Beta Was this translation helpful? Give feedback.
-
A Foreign Function Interface (FFI) is a powerful mechanism which can be used to interact with code written in other languages. Also, some of the considered features (e.g. effects) cannot be exposed to the C side at all, without exposing the complete internal ABI. The proposed syntax for foreign imports and exports is:
The ABI used by types will need to be deeply documented. |
Beta Was this translation helpful? Give feedback.
-
Mixfix operators allow customizing the grammar of Zilch expressions (understand values and types) by indicating how some expressions may be syntactically formed. These kinds of operators never made it into mainstream programming languages (only a few programming languages support these, e.g. Agda or Coq) because of how complex they are to parse (ambiguities happen very quickly: which There are 4 kinds of mixfix operators:
Ambiguities really come from mixing prefix, postfix and infix operators (closed operators do not have ambiguity problems). Every hole in a mixfix operator declaration should be separated by a non-reserved non-blank word. For example, |
Beta Was this translation helpful? Give feedback.
-
GADTs and records allow structuring data in specific “or” branches or “and” groups.
GADTs can be declared using the data Maybe {l : Level} (a : type l) :=
val just : a -> Maybe a
val nothing : Maybe a Records can be declared using the syntax in this example: record tuple-2 {l : Level} (a b : type l) :=
constructor _×_
val fst : a
val snd : b Note that Both GADTs and records can be pattern matched on, using the |
Beta Was this translation helpful? Give feedback.
-
There are a few cases where lazy evaluation is needed, e.g. to define custom control structures. let if_then_else_ {0 l} {0 α : type l} {0 ε : effect} (1 cond : bool) (t : lazy α ε) (e : lazy α ε) : ε α :=
match cond with
true -> t
false -> e
In some programming languages with first-class support for lambda expressions, people tend to use nullary functions to express "to be executed" computations. There are 3 alternatives which can be considered:
|
Beta Was this translation helpful? Give feedback.
-
Implicit parameters augment the language with inference extension to automatically determine some function/data/record parameters. In Zilch, they are specified using the The compiler then treats them as placeholders which must be statically resolved without requiring user input (failure to do so yields a compile-time error about an unresolvable implicit argument). If the implicit argument is of a record type, it can also be |
Beta Was this translation helpful? Give feedback.
-
An improvement over "normal" modern low-level programming languages is the use of "quantities" (or "usages") to specify the compile-time/runtime of some expressions.
A great addition to such system is "usage polymorphism", meaning that some values can have an "unknown" usage at declaration site, which will thereby be monomorphised (or not, up to the implementation) at call-site. This idea is present in Frank, although its type system is actually linear, not quantitative. let id{0 k, 0 A}(k x : A) ≔ x Here, Usage-variables will always need to be qualified with a |
Beta Was this translation helpful? Give feedback.
-
One of the main goals of Zilch is to reduce the amount of undefined behaviors through type safety.
However, some features also provide quality of life when using the language itself.
Notation used for the remaining of this post:
This list might get modified at some point, depending on how the language evolves. This is the current state for Zilch:
Linear/Affine typesRegions (with capabilities? see the calculus of capabilities)An area system much like regionsReference capabilities (see Introduce reference capabilities in Zilch #6)ω
multiplicity of QTT)✨ Row polymorphism with anonymous records and polyvariants✨ Safe ad-hoc polymorphism using typeclasses and implementationsu64
vs*u64
or&u64
; some types may be boxed by default without explicit markers)💡 Some specific kind of bitfields💡 Static (compile-time) contractsNote: all of these features are the currently planned ones for the first two versions of Zilch. The second version of Zilch (and in fact, the first version also²) should be completely bootstrapped from the original, minimal Zilch compiler written in Haskell.
¹: Problems arise when using any other kind of "resource" than memory (files, sockets, shared memory, ...) for all alternatives proposed other than linear/affine types and reference capabilities.
²: The first version of the compiler will firstly be written in Haskell, then fully rewritten in Zilch. This will take time, but as we do not add any feature whatsoever during this process, the major version should not be changed (according to semantic versioning).
Beta Was this translation helpful? Give feedback.
All reactions