7 ms·
Sky – an Elm-inspired language that compiles to Go
- zem 7mo agoat first glance this looks amazing! basically provides everything I have ever wanted in a full stack language. looking forward to experimenting with it. edit: looking through the docs/examples some more, it looks like javascript interop is fairly clunky, both because it relies on string concatenation to embed fragments of javascript, and because the string concatenation syntax is not great (and the formatter makes it even worse - see the example at https://github.com/anzellai/sky/blob/main/examples/13-skyshop/src/Lib/OAuth.sky https://github.com/anzellai/sky/blob/main/examples/13-skysho...) I would encourage you to at the least add multiline strings with interpolation support, and ideally add a small compiler for html literals.
- anzellai 7mo agoThanks for taking your time to look at the repo! yes I have built so many applications and worked at startups/scaleups where different languages / type systems are used for frontend/backend, and very often we need to bring in schema generation like OpenAPI, protobuf/connectrpc etc. to code generate types/apis that can be shared between teams. But that's ugly and hard to maintain & scale. I love Elm's ergonomics & Go's simplicity, and Sky is really my serious take to bring 1 language for full stack application (well, at least to cater for most common application types). back to your feedback, indeed, the multi-line string is one of the things that bug me as well. They only surface when I start building incremental examples -- skyshop is a realworld like example which expose a bunch of issues & compiler limitations. That said, my goal is for devs not needing to write/embed JS in Sky code, but perhaps serve as static, and have Sky semantic to "load/init" the JS. Nonetheless the ugly multi-line string issue is now addressed with https://github.com/anzellai/sky/pull/13 https://github.com/anzellai/sky/pull/13. HTML I took similar of Elm to have elements as function, and have an escape hatch using node for custom elements. I use VNode rather than string for HTML rendering, as that's much more efficient in diffing and for Sky.Live SSE push for updates. Anyhow, please feel free to check on Sky repo regularly and hopefully I will make enough progress sooner that Sky is useable in realworld side projects.
- zem 7mo agoawesome! will definitely check back regularly.
- riclib 7mo agoCan’t wait to play with it. Great design!
- skybrian 7mo agoFunctional languages have some good and some bad features and there's no reason to copy them all. For example, you don't need to have a Hindley-Milner type system (bidirectional is better) or currying just because it's a functional language.
- troupo 7mo agoWe need more pragmatic languages. E.g. Erlang and Elixir are functional, but eschew all the things FP purists advocate for (complex type systems, purity, currying by default etc.)
- zem 7mo agoocaml has a complex type system but it's also very pragmatic in that it doesn't force you into any one paradigm, you can do whatever works best in a given situation. (scala arguably goes further in the "do whatever you want" direction but it also dials the complexity way up)
- troupo 7mo agoYes! Completely forgot about OCaml because I only spent a couple of months with it
- phplovesong 7mo agoOcaml's typesystem is rich, but not as complex as TypeScripts. It seems TS just adds more obscure features every year for little benefit.
- rapind 7mo agoIf you like Erlang, Elixir, and Elm/Haskell, then Gleam + Lustre (which is TEA) is a pretty great fit.
- deleted 7mo ago[deleted]
- melodyogonna 7mo agoThat's two new languages compiling to Go making HN frontpage in as many days. It seems people like everything about Go except the language itself. Me? I like everything about Go including the language, these transpiled languages are interesting though. But I keep wondering if they could integrate at a lower-level than the source code. Like how JVM languages integrate at the bytecode level, or LLVM languages at the LLVM level
- MichaelNolan 7mo ago> But I keep wondering if they could integrate at a lower-level than the source code. I’m sure they could, but targeting go source code has the benefit of giving early adopters an escape hatch. If it targeted LLVM directly, I would never consider using this at work since the risk of it being abandoned is too high. But since it targets go source, I would perhaps consider it for some low importance projects at work.
- seabrookmx 7mo agoThe standard go toolchain doesn't use LLVM. Go has its own assembly format and machine code generation.
- ksec 7mo agoIf we think of Go as different kind of C, then having Go as a compiled target seems to make sense as C is a compiled target.
- flossly 7mo agoI dont get your reasoning.
- onlyrealcuzzo 7mo agoWhat was the other one? I'm working on a language that transpiles to Zig with a custom Go-like runtime (and no garbage collector, Rust-style Affine movement instead). Sky seems quite cool, as it's additive to Go in interesting ways. I originally considered keeping the GC and just transpiling to Go so I didn't need to write a Runtime. Go rules! It really does. But I HATE writing/reading Go. So I'm glad more people are doing this!
- tasuki 7mo agoA bit too bleeding edge for me, but it does look super nice (ie exactly like Elm).
- redoh 7mo ago[flagged]
- flossly 7mo agoThe resulting binary is, well, binary. Not Go. Or I miss something.
- submain 7mo agoGreat work :). Go doesn't have TCO. That means functional languages (no for loops) could blow up the stack. How did you solve that?
- kubb 7mo agoYou can just compile any tail recursive function to a function with a loop and no recursion.
- adamwk 7mo agoRight but recursion is only a smaller part of why the optimization is important. It means tail-called functions still build on the stack and long function chains—as is common with fp—can overflow
- 1-more 7mo agoThis is in fact how Elm does it! Tail call recursion compiles to a while loop.
- deleted 7mo ago[deleted]
- srean 7mo agoThat does not address the use case where I find tail recursion most tempting. That would be mutually recursive functions. If the function can be written as an idiomatic loop I probably would do so in the first place.
- 1-more 7mo agoI will add this to my list of Elm-inspired tools that call to mind Brian Eno's quip about the first Velvet Underground album: "I think everyone who bought one of those 30,000 copies started a band!" With Elm it feels like it's 1% of Elm users creating a language. https://quoteinvestigator.com/2016/03/01/velvet/ https://quoteinvestigator.com/2016/03/01/velvet/
- bbkane 7mo agoYou should publish your "Elm-inspired tool" list- I bet it's pretty large. Off the top of my head: iced, react redux, bubble tea (Go lib), Roc lang. I'm sure there are lots more. I'm still waiting for someone to write an "Elm retrospective" and examine its rise and stagnation
- 1-more 7mo agoI left this comment a while back https://news.ycombinator.com/item?id=45752905 https://news.ycombinator.com/item?id=45752905 when someone asked what was up with Elm at the current moment. I left a bunch off. - Evan entered hermit mode to create Acadia, a language for an Elm-like experience querying the database. He's given conference talks about it but none have been recorded. https://acadia.engineering/ https://acadia.engineering/ This seems to have the same goals as Lamdera. - Evan hinted that 0.19.2 is coming and has asked for help profiling it https://discourse.elm-lang.org/t/help-me-profile-elm-0-19-2-compiler-speed/10521 https://discourse.elm-lang.org/t/help-me-profile-elm-0-19-2-.... In the meantime the ecosystem is getting crazy evolved. Turns out not changing the language under your feet for a few years leads to lots of development with what's currently there. Frameworks like elm-pages allowed for command line utils in Elm like elm-codegen. Elm-review lets you write linting rules with autofixes unlike anything I've used in other languages. A few people are writing forks and non-forks that target more than the browser or self-host the compiler. Every backend language I've used with decent types has a package to generate Elm types (and their decoders, and a nice way to interact with the JSON API, and deal with glue code generally). Literal forks of Elm compiler - Gren (general purpose lang targeting browser, CLI, servers) https://gren-lang.org/ https://gren-lang.org/ - Zokka (fixes a few compiler bugs and allows for custom package repos) https://discourse.elm-lang.org/t/a-new-zokka-version-bringing-private-package-repositories/9811 https://discourse.elm-lang.org/t/a-new-zokka-version-bringin... - Guida (self-hosted compiler) https://guida-lang.org/ https://guida-lang.org/ Forks that do not ever seek to change the syntax of the language and thus compile .elm files - Lamdera ("non-fork" fullstack with evergreen migrations) https://dashboard.lamdera.app/docs/starting https://dashboard.lamdera.app/docs/starting - Eco (written in Elm targeting x86 binaries via MLIR and LLVM) https://github.com/eco-lang/eco-runtime https://github.com/eco-lang/eco-runtime - Elm-run (targeting CLI and servers, self hosted) https://elm-run.dev/roadmap https://elm-run.dev/roadmap Languages inspired by it whose creators are big Elm users: - Roc (general purpose): https://www.roc-lang.org/faq https://www.roc-lang.org/faq - Gleam (targets Erlang VM and browser) https://gleam.run/cheatsheets/gleam-for-elm-users/ https://gleam.run/cheatsheets/gleam-for-elm-users/ - Cara https://cara-lang.com/ https://cara-lang.com/ Things that use the Elm architecture in other languages (linking to pages that mention the connection where possible): - Foldkit (Typescript) https://discourse.elm-lang.org/t/foldkit-the-elm-architecture-in-typescript-powered-by-effect/10579 https://discourse.elm-lang.org/t/foldkit-the-elm-architectur... - Iced (Rust): https://book.iced.rs/ https://book.iced.rs/ - Bubble Tea (Go): https://github.com/charmbracelet/bubbletea https://github.com/charmbracelet/bubbletea - Lustre (Gleam): https://github.com/lustre-labs/lustre https://github.com/lustre-labs/lustre - A list of TEA-in-Swift and React in Swift: https://gist.github.com/inamiy/bd257c60e670de8a144b1f97a07bacec https://gist.github.com/inamiy/bd257c60e670de8a144b1f97a07ba... - Redux (Javascript/Typescript): https://redux-toolkit.js.org/rtk-query/comparison https://redux-toolkit.js.org/rtk-query/comparison If you read this far and are wondering which to check out, I cannot endorse Lamdera enough. Use the same types from your DB to your frontend and write zero glue code. Migrations required to update the running frontend/backend whenever you change anything. Really changes the way you write code.
- onlyrealcuzzo 7mo agoFirst - awesome job. Congrats. Self hosting is an accomplishment! But I'm curious to get your thoughts on the process in hindsight. I understand why it's valuable: to cast a wide net in catching bugs and give a good signal that your language is generally "ready". I'm working on a similar language, but worried about going down the self-hosting path, as I think it'd slow me down rather than speed me up. How did it work for you?
- ModernMech 7mo agoWhat's the actual accomplishment here? It seems like the language came into existence a month ago and was written mostly by Claude. If self hosting is a matter of asking Claude to do it and it takes a couple weeks, is it really an accomplishment at all?
- troosevelt 7mo agoYes, somebody has to actually do it, and they did.
- onlyrealcuzzo 7mo agoAnything + Go's runtime is a reasonable language. Go's runtime is one of the greatest pieces of software ever built. Assuming this works - which self-hosting guarantees a minimum level of "working" - this is useful! I didn't want to rely on the unpredictability of a garbage collector, so I chose to build my own runtime, but it's not going to be as good as Go any time soon.
- Philpax 7mo ago"I could have made that!" "Yes, but you didn't."
- eeue56 7mo agoDerw, a human written Elm fork by me, is largely self-hosted. I took that decision with inspiration from Go: 1) it gave me a large codebase which could be used to assess language features on and 2) it gave me motivation to improve generalized performance rather than focusing on the niche use cases (web-rendering).
- harikb 7mo agoSomewhat unrelated to the language itself: > The compiler bootstraps through 3+ generations of self-compilation. I guess it applies to any language compiler, but f you are self-hosting, you will naturally release binary packages. Please make sure you have enough support behind the project to setup secure build pipeline. As a user, we will never be able to see something even one nesting-level up.
- troad 7mo agoI feel like there's too much of a fetish for self-hosting. There's this pernicious idea that a language isn't a 'real' language until it's self-hosted, but a self-hosted compiler imposes real costs in terms of portability, build integrity, etc. If I ever write a compiler - God forbid, because language design is exactly the kind of elegance bike-shedding I'll never crawl my way out of - it's going to be a straight-up C89 transpiler, with conditional asm inlines for optional modern features like SIMD. It would compile on anything and run on anything, for free, forever. Why would I ever give that up for some self-hosting social cachet?
- p1necone 7mo agoIf you wrote the C89 outputting transpiler in your own language it would still be just as portable.
- troad 7mo agoI'd be dependent on pre-existing binaries that are closely wedded to a particular platform (OS, libc etc), and it over time it would become more and more difficult to attest to build integrity / ensure reproducible builds. (Is the ARM build meant to run an x64 emulator as part of some lengthy historic bootstrapping process?)
- mrichman 7mo agoCompiles to Go or transpiles to Go?
- farfatched 7mo agoEither is fine. ``Formally speaking, "Transpiler" is a useless word'' https://people.csail.mit.edu/rachit/post/transpiler-formal/ https://people.csail.mit.edu/rachit/post/transpiler-formal/
- 9rx 7mo agoYou are free to use whatever word you want. Even "bloopydoopy", if you so wish. But "compiles" is best.
- __natty__ 7mo agoI would love to see Java inspired language compiled to Go. I really like Go portability and standard library and Java... verbosity. I prefer explicit names, types and all the syntax around that. Graalvm is not an answer for me because as far as I'm aware it doesn't support cross-compile.
- weavie 7mo agoYou could make it happen in about a week and $50 worth of tokens.
- ch4s3 7mo agoIf you allow FFI are you really inspired by Elm? ;)
- zem 7mo agothey're inspired by repeating elm's good features and fixing the bad ones!
- librasteve 7mo agoVery cool. I am comparing this https://github.com/anzellai/sky#tea-architecture https://github.com/anzellai/sky#tea-architecture with this https://harcstack.org https://harcstack.org (my thing) ... guess I have some work to do ;-)
- taolson 7mo agoNice to see another language with Haskell / Miranda type syntax, but the vibe-coded implementation sure shows: e.g. src/Compiler/Infer.sky isUpperStart: isUpperStart : String -> Bool isUpperStart name = case String.slice 0 1 name of "A" -> True "B" -> True "C" -> True ... for 23 more cases. And the corresponding go code in the bootstrap compiler is even worse.
- toastal 7mo agoHaskell/Miranda use `::` instead of `:` for type signatures unlike Elm & basically the rest of the family which prioritize types being less keypresses than list cons.
- taolson 7mo agoSorry, I meant "Haskell / Miranda style syntax" -- e.g. curried functions, concise syntax with little boilerplate, etc. The word type is too overloaded ;-)
- deleted 7mo ago[deleted]
- bonesss 7mo agoI started my career cleaning up systems written by solo devs in the pre internet era. I’ve seen a lot of starts_with_UCase() implementations like that. I see now I’m going to end my career cleaning up systems written by chronically online vibe coders, making all the same mistakes, with none of the excuses.
- voidUpdate 7mo agoDoes this language use ASCII or Unicode strings? I think this implementation is technically correct for the strict subset of ascii characters, but as soon as you add more, it stops working. EG I'm pretty sure Á or Ó are capitals, and are included in Windows-1252 which is apparently extremely common in non-unicode strings, and there are a huge amount of unicode characters that are uppercase, in which case this function isn't even slightly correct
- desireco42 7mo agoElm is a language I enjoyed the most. I love Ruby, I loved some other languages, even Haskell I enjoyed, but Elm is special. So let's make this work. Now that you got foundation created, let's see how to move it forward.
- danpalmer 7mo agoWow, this is amazing. I always wanted to love Haskell but never really managed, Elm nailed the balance of usability and correctness, plus the architecture was beautiful. I've never liked Go, but its strengths are absolutely compiling to single binaries, fast compile times, and concurrency primitives (not necessarily using them) etc. Compiling to Go is a great idea.
- MegagramEnjoyer 7mo agowow this is pretty cool!
- linzhangrun 7mo ago[flagged]
- flossly 7mo agoI think you have an interesting spot in the design space here... Have you seen Lamdera? They have a way to use Elm on the server-side that is supposedly acceptable to the Elm-BDFL Evan Czaplicki. https://lamdera.com/ https://lamdera.com/ This talk explains it well: https://www.youtube.com/watch?v=4T6nZffnfzg https://www.youtube.com/watch?v=4T6nZffnfzg Sky does all on the server (more popular lately with HTMX and LiveView), where Elm+Lamdera is basically 2 project and Lamdera ties you into a propietary-ish ecosystem.
- mhitza 7mo agoGiving even a modicum of care of what Evan has to say in 2026 is a good joke. Only thing he's known outside the Elm community (aside from Elm) is how to antagonize your own community.
- rkangel 7mo agoKeeps saying "no websocket required" like it's a good thing. The JS client (https://github.com/anzellai/sky/blob/main/docs/design/sky-live.md https://github.com/anzellai/sky/blob/main/docs/design/sky-li...) seems to rely on long polling. Phoenix LiveView (the inspiration) defaults to using WebSockets because it's much more efficent, but falls back to Long polling if not available.
- anzellai 7mo ago[dead]
- mmstghjx 7mo agoThis is awesome! I love Haskell's syntax, but its adoption isn't where I'd like it to be. One thing that I don't see is a way to mitigate the "andThen" pyramid of doom. This happens when you have a language without early returns and you have chain multiple Result returning operations. You can use nested case expressions: case operation1 x of Ok value -> case operation2 value of Ok value2 -> value2 Err msg -> "error from operation2: " ++ msg Err msg -> "error from operation1: " ++ msg Or nested `andThen` calls operation1 x >> mapError (\msg -> "error from operation1: " ++ msg) >> `andThen` (\value -> operation2 value) >> mapError (\msg -> "error from operation2: ++ msg) This is nicer to read, but still a lot of noise. Haskell has `do` notation to alleviate this but that brings with it the type-class that shall not be named. Some languages, like Rust, introduce different per-type syntactical solutions such as `async/await` for Promises and `?` for Result. I particularly like Gleam's `use` notation, which is syntactical sugar around functions that take a callback as their final argument. Do you have a solution for this in Sky?
- anzellai 7mo ago[dead]