Sky is a pure functional ML-family language that compiles to Go.
Hindley-Milner types, algebraic data types, fully-typed Go codegen — one binary, three UI backends.
curl -fsSL https://raw.githubusercontent.com/anzellai/sky/main/install.sh | sh
module Main exposing (main)
import Std.Ui as Ui exposing (Element)
import Std.Ui.Font as Font
import Std.Live exposing (app, route)
type alias Model = { count : Int }
type Msg = Increment | Decrement | Reset
init _ = ({ count = 0 }, Cmd.none)
update msg model =
case msg of
Increment -> ({ model | count = model.count + 1 }, Cmd.none)
Decrement -> ({ model | count = model.count - 1 }, Cmd.none)
Reset -> ({ model | count = 0 }, Cmd.none)
view : Model -> Element Msg
view model =
Ui.column [ Ui.spacing 16, Ui.padding 24 ]
[ Ui.el [ Font.size 48, Font.bold ]
(Ui.text (String.fromInt model.count))
, Ui.row [ Ui.spacing 8 ]
[ Ui.button [] { onPress = Just Decrement, label = Ui.text "-" }
, Ui.button [] { onPress = Just Reset, label = Ui.text "reset" }
, Ui.button [] { onPress = Just Increment, label = Ui.text "+" }
]
]
main = app { init = init, update = update, view = view
, subscriptions = \_ -> Sub.none
, routes = [ route "/" () ], notFound = () }
The same init / update / view runs on three runtimes — pick at the entry point, no view-code changes:
Cmd.performStd.Ui is a typed, no-CSS layout DSL. Swap one import to retarget — web, terminal, CLI — with zero changes to view, update, or model.
import Std.Live exposing (app)
main = app
{ init = init, update = update
, view = view, subscriptions = subs
, routes = [ route "/" () ]
, notFound = () }
HTTP + SSE wire. Persistent sessions across deploys (memory / SQLite / Redis / Postgres / Firestore). Async Cmd.perform goroutines. Input-authority protocol preserves typed input across re-renders.
import Std.Tui as Tui
main = Tui.app
{ init = init, update = update
, view = view, subscriptions = subs
, onKey = KeyPressed
} |> Task.run
Render Element trees to ANSI cells. Logical-pixel canvas (1280×720 default), mouse left-press + scroll wheel, wide chars + emoji via grapheme-cluster width. Diff renderer; no flicker.
import Std.Cli as Cli
main = Cli.program
{ init = init, update = update
, view = view, subscriptions = subs
, onLine = LineRead
} |> Task.run
Line-oriented event loop for non-TTY shells. Same TEA shape; view returns a string each turn. Echo-suppressed password reads via Cli.readPassword for auth flows.
Hindley-Milner type inference, exhaustive pattern matching, no null, no exceptions. Undefined names caught at compile time with line:col positions.
Compiles to a native Go binary. Your fullstack app — API, database, server-rendered UI — ships as one file. The compiler itself is also a single binary (Haskell).
Std.Ui is a typed no-CSS layout DSL. The same view renders to a web app (Sky.Live), a terminal UI (Sky.Tui), or a stdin loop (Sky.Cli). One model, three runtimes.
Import any Go package with auto-generated type-safe bindings. Stripe, Firebase, SQLite, PostgreSQL — all with panic recovery and nil safety.
v0.13 codegen emits typed Go for every reachable Sky symbol — no interface{} for user functions, vars, lambdas, or ADTs. Stripe-scale FFI surfaces tree-shaken whole-program (76k symbols → only what you reach).
Built-in database (Std.Db), authentication (Std.Auth), JSON encode/decode with pipeline, HTTP server, formatter, LSP with hover + diagnostics.
-- Typed onSubmit decodes formData
-- directly into a record arg
Ui.form [ Ui.onSubmit DoSignIn ]
[ Input.email [] cfg.email
, Input.currentPassword [] cfg.pwd
, Ui.button [] btn
]
describe shape =
case shape of
Circle r ->
"circle r=" ++ String.fromFloat r
Rectangle w h ->
"rect"
import Std.Db as Db
-- reads sky.toml [database]
todos = Db.connect ()
|> Task.andThenResult (\db ->
Db.queryDecode db
"SELECT * FROM todos"
[] todoDecoder)
-- Run tasks in background goroutines
update msg model =
case msg of
FetchData ->
( model, Cmd.perform
(Http.get "/api") GotData )
-- Parallel HTTP requests (goroutines)
fetch =
Task.parallel
[ Http.get url1
, Http.get url2
]
|> Task.andThen handleAll
import Stripe
-- whole-program DCE strips
-- unused symbols (76k → only used)
charge = Stripe.newCharge ()
|> Result.andThen ...
Standalone tools, libraries, and full applications.
E-commerce app with Stripe payments, Firebase auth, Firestore, i18n, Tailwind CSS. Full Sky.Live TEA architecture with async commands.
examples/13-skyshop →Chess game with negamax AI, SQLite persistence, and SSE real-time updates. Full move validation, castling, en passant, promotion.
examples/16-skychess →Encrypted environment variable manager. AES-256-CBC SQLite, portable across machines, six commands. Single 8MB binary.
github.com/anzellai/sky-env →Tailwind CSS utility classes for Sky.Live apps. Type-safe, composable, zero-runtime — class names checked at compile time.
github.com/anzellai/sky-tailwind →Roadmap voting app — Sky.Live, Std.Auth (bcrypt + sessions), Std.Db (SQLite), email verification, key rotation.
examples/12-skyvote →Service monitoring dashboard with metrics, alerts, and incident timeline. Real-time updates via SSE subscriptions.
examples/17-skymon →Reddit/HN-style forum on the typed no-CSS layout DSL. Per-user vote tracking, threaded comments, password-manager-friendly forms.
examples/19-skyforum →Install in seconds. Create your first project. Ship a binary.
curl -fsSL https://raw.githubusercontent.com/anzellai/sky/main/install.sh | sh
sky init my-app
cd my-app
sky run