Language syntax
Status: the Rust compiler (
rust/,cargo build --release -p sky) is the primary Sky compiler; the Haskell compiler is preserved underlegacy-haskell-compiler/. Verified by the example sweep + compiler test suite (cargo test+ xtask gates). See../compiler/versions.mdfor the changelog.
Sky's surface syntax is Elm-compatible: most expressions that parse in Elm also parse in Sky. (See NOTICE.md for prior-art attribution; programming-language syntax is not itself copyrightable.)
A module
module Lib.Counter exposing (Counter, init, increment)
import Sky.Core.Prelude exposing (..)
type alias Counter =
{ value : Int
, step : Int
}
init : Counter
init =
{ value = 0, step = 1 }
increment : Counter -> Counter
increment c =
{ c | value = c.value + c.step }
Types
- Primitives:
Int,Float,String,Bool,Char,Bytes. - Records:
{ name : String, age : Int }. The parser accepts inline record types in annotations (f : { name : String, age : Int } -> String), though sharing a record shape across functions still reads better as a namedtype alias. - Tuples:
( Int, String )— 2-tuples emitrt.SkyTuple2, 3-tuples emitrt.SkyTuple3, 4+ emit the slice-backedrt.SkyTupleN. - Lists:
List a. - Dicts:
Dict k v(runtimemap[string]any; see types.md for caveats). - ADTs:
type Shape = Circle Float | Rect Float Float. - Functions:
Int -> Int -> Int(right-associative). - Type variables:
a,b,c— lowercase identifiers are HM polymorphic.
See types.md for the full type story.
Functions
-- Top-level function with annotation
add : Int -> Int -> Int
add x y =
x + y
-- Anonymous function (lambda)
doubler =
\x -> x * 2
-- Partial application
addFive =
add 5
Let / in
area radius =
let
pi = 3.14159
square x = x * x
in
pi * square radius
Case / of
describe n =
case n of
0 ->
"zero"
_ ->
if n > 0 then
"positive"
else
"negative"
Pattern matching is exhaustive — missing ADT variants or missing True/False in boolean matches are compile errors. See pattern-matching.md.
Pipelines
result =
input
|> String.trim
|> String.toLower
|> String.split ","
|> List.map String.trim
|> List.filter (not << String.isEmpty)
|> is left-to-right function application. <| is the reverse.
Record update
updated =
{ user | email = "new@example.com", age = user.age + 1 }
Multiline strings
html =
"""<div class="card">
<h1>{{title}}</h1>
<p>{{description}}</p>
</div>"""
-
Preserves newlines and indentation.
-
{{expr}}for interpolation (identifier, qualified name, field access, or function call). -
Single
{is literal — safe for CSS, JSON, SQL, JS. -
Backslash escape:
\{{emits a literal{{(no interpolation). Useful for shipping Mustache / Handlebars / shell-script placeholders verbatim:template = """Hello \{{NAME}}, welcome to {{appName}}!""" -- → "Hello {{NAME}}, welcome to MyApp!"\\collapses to a single literal backslash. Other\Xsequences are preserved verbatim (so regex / paths like\d+/\testare unaffected).
Operators
| Operator | Meaning |
|---|---|
| ` | > <|` |
:: | Cons onto list |
++ | Concatenate string / list |
<< >> | Function composition |
+ - * / // | Numeric — // is integer division |
== /= < > <= >= | Comparison |
&& || | Boolean |
No custom operators — language constraint.
Comments
-- line comment
{-
block comment
can span lines
-}
Reserved words
module, exposing, import, as, type, alias, if, then, else, case, of, let, in.
Non-reserved identifiers frequently used in Sky but which are not keywords: from, where.
Known limitations
- No anonymous record types in function signatures. Define a
type aliasfirst. - No higher-kinded types / type classes / row polymorphism — intentional.
- No custom operators.
- Negative literal arguments need parentheses:
f (-1)notf -1(matches Elm's parser disambiguation).