[HN Gopher] Loon: A functional lang with invisible types, safe o...
___________________________________________________________________
Loon: A functional lang with invisible types, safe ownership, and
alg. effects
Author : surprisetalk
Score : 71 points
Date : 2026-02-20 21:45 UTC (1 days ago)
(HTM) web link (loonlang.com)
(TXT) w3m dump (loonlang.com)
| phpnode wrote:
| The pattern matching example has a type Shape which is never
| referenced and this seems to conflict with the idea that you
| never write a type, am I missing something obvious?
| KPGv2 wrote:
| I think they mean you never write types for your variables or
| functions. They don't mean you can't create types. That's the
| reference to Hindley-Milner type system and type inference. You
| don't have to say
|
| x : Nat x = 5
|
| You just say x = 5
|
| I personally don't like that you don't seem to be able to
| manually describe the type for a fn/var, because it's very
| useful when prototyping to write stubs where you provide the
| typedef but then the actual variable/function is just marked as
| "todo"
| weitendorf wrote:
| Very cool! I've been flirting with the idea of biting the bullet
| and moving more towards language extensions around protobuf/grpc
| vs just tools so it's really great to see projects on the other
| side of that kind of decision shipping and what choices they made
|
| Why the square brackets in particular? Notation is such an
| annoying part of this stuff, I'm actually leaning towards pushing
| a lot of structure to the filesystem
| luckymate wrote:
| I think I am in love. Clojure + Rust, everything is typed, but I
| don't need to annotate. And algebraic effects that I really
| wanted to explore in Ocaml, but now can do it in language with
| way easier syntax. I might be missing bit of Clojure dynamic
| nature, but it looks like a bunch of really interesting ideas in
| one language.
| christophilus wrote:
| Yeah. Clojure is by far my favorite dynamic language. But, I
| love static types. At a glance, a quick glance at Loon- looks
| like it could just flat out become my favorite language. Loon
| with a standard library that approaches Go's would be
| :chefskiss:
| drob518 wrote:
| Coming from Clojure, I like types being invisible. Square
| brackets feels like a needless change. If you want sexprs, just
| use sexprs. Interesting ideas, as you say.
| ecto wrote:
| <3
| xigoi wrote:
| Looks great! However, the website is really slow. Every page
| takes several seconds to load and trying to open the reference
| freezes my browser.
| ethmarks wrote:
| Apparently the site itself is written in Loon. The HTML is just
| a static shell that loads a `boot.js` script[1] that runs some
| WASM that compiles and evals the Loon source files. I found the
| source code here[2].
|
| Definitely cool in concept, but very performance-intensive and
| slow.
|
| [1]: https://loonlang.com/boot.js
|
| [2]: https://github.com/ecto/loon/tree/main/web
| mapcars wrote:
| I'm assuming the website is written in Loon and according to
| roadmap its version 0.4 and compilation is planned in 0.7. So
| it demonstrates that the language works, but its not optimised
| yet.
| ecto wrote:
| exactly! I didn't post this (thank u whoever did though) so
| wasn't ready to launch yet. but the idea is it will SSR and
| hydrate each page. I want to pull it all out into a framework
| congruent to Next.js
| davidee wrote:
| Perhaps relevant: https://campedersen.com/loon
|
| This looks like a really neat project/idea; seeing the road map
| is exciting too, nearly everything I'd want.
|
| I don't love the brackets syntax, or the [op val1 val2] ([* x x])
| style, but I appreciate the attempt at clarity and consistency
| and none of these things are dealbreakers.
|
| I do wonder why they've leaned so hard into talking about the
| type system being out of sight. Again, not a dealbreaker, but I
| feel strongly that explicit typing has a place in codebases
| beyond "describe something because you have to".
|
| Strongly typed languages strike me as providing detailed hints
| throughout the codebase about what "shape" I need my data in or
| what shape of data I'm dealing with (without needing to lean on
| an LSP). I find it makes things very readable, almost self-
| documenting when done right.
|
| From their docs about their choices: "The reasoning is simple:
| types exist to help the compiler catch your mistakes. They do not
| exist to help you express intent, at least not primarily." This
| strikes me as unnecessarily pedantic; as someone reading more
| code than I write (even my own), seeing a type distinctly--
| particular as part of a function signature--helps me understand
| (or add strong context) to the original author's goal before I
| even get to reading the implementation.
|
| I find this doubly so when working through monadic types where I
| may get a typed error, a value, and have it all wrapped in an
| async promise of some kind (or perhaps an effect or two).
|
| By the same token many languages allow you to leave out type
| annotations where they may be simple or clearly implied (and/or
| inferred by the compiler), so again, I'm not understanding the
| PoV (or need) for these claims. Perhaps Loon simply does it
| better? Am I missing something? Can I write return types to stub
| functions?
|
| From the above blog post: "That's how good type inference feels!
| You write code. The types are just there. Because the language
| can see where it's going." Again, it feels strongly geared
| towards a world where we value writing code over
| reading/maintaining/understanding code, but maybe that's just my
| own bias/limitations.
|
| Will follow it closely.
| wk_end wrote:
| Yeah, the idea that types exist just to help the compiler catch
| your mistakes shows a depressingly superficial understanding of
| the benefits of static typing.
|
| Types exist so that the compiler can reason about your code
| better - but not incidentally, they also help _you_ reason
| about your code better!
|
| To wit: even when working in dynamic languages, it's often
| considered a good practice to write down in docstrings the
| types of objects a function can operate on, even without static
| enforcement. Thinking about types is helpful for humans, too.
|
| And it's not even just a thing to help you read code in the
| future - types help me _write_ code, because as I sit down to
| write a function I know the possible values and states and
| capabilities of the object I 'm working with. In the best of
| cases I can analytically handle all the possible cases of the
| object, almost automatically - the code flows out of the
| structure of the type.
| bossyTeacher wrote:
| > Types exist so that the compiler can reason about your code
| better - but not incidentally, they also help you reason
| about your code better!
|
| THIS. So much. This observation is extremely intuitive to me.
| cptroot wrote:
| Good news, there's a line in the "Coming from Rust"[1] page
| that says
|
| > You never annotate a function signature unless you want to
| for documentation purposes.
|
| so it sounds like function annotation is still an option for
| the purposes of communication, just no longer required in all
| cases.
|
| [1] https://loonlang.com/concepts/from-rust
| cptroot wrote:
| Aha, here's the syntax in case you're curious (using an
| example lifted from the playground) [type
| Shape [Circle f64] [Rect f64 f64]
| Point ] [sig test_sig : Shape -> Float]
| [fn test_sig [shape] [match shape [Circle
| r] [* 3.14159 [* r r]] [Rect w h] [* w h]
| Point 0.0 ] ]
|
| Unfortunately it seems like this doesn't currently work as
| expected when I use it in the playground, so I'm going to go
| file an issue
| ecto wrote:
| thank you <3 I will fix asap
| mapcars wrote:
| > Strongly typed languages strike me as providing detailed
| hints throughout the codebase about what "shape" I need my data
| in
|
| I agree that seeing types is helpful, though typing them is
| also not necessary. Perhaps the solution is an IDE that shows
| you all the types inferred by the compiler or maybe a linter
| that adds comments with types on file save.
| zokier wrote:
| > I agree that seeing types is helpful, though typing them is
| also not necessary. Perhaps the solution is an IDE that shows
| you all the types inferred by the compiler
|
| see "The Editor as Type Viewer" section in the docs:
| https://loonlang.com/concepts/invisible-types
| cptroot wrote:
| Neat! I think the website could use a bit more information about
| how the "global" Effect handlers work, and whether it's possible
| to opt-in to that functionality yourself when writing Effects.
|
| That being said I took a look at the roadmap and the next major
| release is the one that focuses on Effects, so perhaps I'm
| jumping the gun a tad. Maybe I'll whip this out for AoC this
| year!
| dxdm wrote:
| > Square brackets replace parentheses for a clean, uniform
| syntax.
|
| Oh dear, why? Abrasive aesthetics aside, this is bad for people
| with certain non-English keyboard layouts. Not me, but many do
| exist.
| IshKebab wrote:
| Better for people _with_ English keyboards though. And I prefer
| the aesthetics.
| Dansvidania wrote:
| Is it better for English keyboards because () are shifted and
| [] are not ?
| dxdm wrote:
| Point taken. I forgot that brackets are not shifted on my
| keyboard.
|
| They do require worse acrobatics than a shift key on a German
| keyboard, though - one of the Alt keys is special and needed
| to trigger them, if memory serves.
|
| Well, that's another argument for everyone to use an English
| layout for coding, I suppose.
| mintplant wrote:
| I got really excited reading this! The docs site is very polished
| and hypes up lots of features which click with things I've been
| wanting out of a language. But then I went to the repository [0]
| and realized that this is a week-old project, with every single
| commit written by Claude. I went to the playground page [1] and
| tried the example for effects, a headline feature and what drew
| me in the most, but it threw an "unbound symbol" error. I thought
| maybe the example could just be out-of-date, so I tried the
| example under the "Algebraic effects" heading on the homepage,
| which shows a different syntax, but that threw a parse error. The
| "Pattern matching" example is supposed to return 78.5, but it
| returns 15.700000000000001 when run in the playground. The
| example for "Mutation" on the ownership docs page [2] throws
| "unbound symbol 'set!'". The "Type Signatures" example from the
| types guide [3] throws another parse error. That's where I
| stopped.
|
| How much of this is actually real?
|
| [0] https://github.com/ecto/loon
|
| [1] https://loonlang.com/play
|
| [2] https://loonlang.com/guide/ownership
|
| [3] https://loonlang.com/guide/types
| ecto wrote:
| hey thank you, should all be fixed now!
| drob518 wrote:
| Yea, kudos on the docs. It's rare that something this new is
| this polished. Well done!
| IshKebab wrote:
| It's such a lot of effort to make a language like this. I don't
| get why they don't just put in like 2% more effort and add syntax
| that makes it less awful for humans. Nobody _really_ wants to
| write `[* 5 5]` do they? [fn square [x] [* x x]]
|
| Could very easily be fn square(x) = x * x;
|
| Or something like that, which is _much_ more readable.
|
| Also
|
| > Hindley-Milner inference eliminates type annotations.
|
| I think it's pretty widely agreed at this point that _global_
| type inference is a bad idea. The downsides outweigh the upsides.
| Specifically: much worse errors & much less readable code.
| mapcars wrote:
| You never used lisp-like languages did you?
| IshKebab wrote:
| No because the syntax is so awful. Programming languages are
| consumed by machines but written by humans. You need to find
| a middle ground that works for both. That's (one of the
| reasons) why we don't all program in assembly any more.
|
| Lisp and similar are just "hey it's really easy to write a
| parser if we just make all programmers write the AST
| directly!". Cool if the goal of your language is a really
| simple parser. Not so cool if you want to make it pleasant to
| read for humans.
| pmcgoron wrote:
| 1. I don't know much about HM systems mathematically, but how do
| the effect handlers interact with type inference? I thought there
| was some issues with automatic inference there.
|
| 2. The macros examples on the website don't show binding
| situations. Are the macro hygienic like in Scheme?
|
| 3. Why the choice of [] over ()?
| ecto wrote:
| good questions
|
| 1. effects are tracked in the type system as row types, so they
| compose with HM inference pretty naturally. the tricky part is
| effect polymorphism. Loon handles that similarly to how koka
| does it, with row polymorphism. no ambiguity issues so far but
| idk
|
| 2. yes, macros are hygienic! documenting some binding
| situations would make a great first PR :)
|
| 3. easier to type!
| kronnpp wrote:
| How is it related to the Standard Meta Language (SML) family of
| languages?
| rivetfasten wrote:
| This looks really nice! I'm excited to see it and am left with
| questions from perusing the site. Let me know if I missed it.
|
| It's simple and also has an excellent choice of where to invest
| in powerful features. It looks like an elegant, minimal selection
| of things existing languages already do well, while cutting out a
| lot of cruft.
|
| The site also mentions two differentiating and less established
| features that make it sound like more than yet another fp remix:
| type-based ownership and algebraic effects.
|
| While ownership stuff is well explored by Rust and a less
| explicit variation by Mojo, this sounds like a meaningful
| innovation and deserves a good write-up! Ownership is an
| execution-centric idea, where fp usually tries to stay
| evaluation-centric (Turing v Church). It's hard to make these
| ideas work will together, and real progress is exciting.
|
| I'm less familiar with algebraic effects, but it seems like a
| somewhat newer (in the broader consciousness) idea with a lot of
| variation. How does Loon approach it?
|
| These seem like the killer features, and I'd love to see more
| details.
|
| (The one technical choice I just can't agree with is multi-arity
| definitions. They make writing code easier and reading it harder,
| which is rarely or never the better choice. Teams discourage
| function overloading all the time for this reason.)
|
| Thanks for sharing!
| ecto wrote:
| thanks for the kind words :)
|
| You're right, ownership and effects are the real
| differentiators. The idea here is to let the compiler discover
| ownership rather than it being declared imperatively
|
| Regarding algebraic effects, Loon uses continuations similar to
| Koka but more restrictive. Effects are declared with
| operations, and every side effect (IO, failure, async, state)
| is an effect that propagates through the call graph. The
| interesting part is `handle`, which lets you intercept effects:
| [handle [load-config "app.toml"] [IO.read-file path]
| [resume "mock contents"] [Fail.fail msg] "default"]
|
| Handling an effect subtracts it from the function's effect
| setso a function that handles all its IO internally is pure
| from the outside. This replaces exceptions, async/await, DI,
| and mocking with one mechanism. Testing is just handling
| effects with test data
|
| Multi-arity: get lost! fork me?
| netbioserror wrote:
| True beauty. Wow. My only ask would be optional type annotations
| for function and type parameters, so it's easy to fully describe
| your interfaces in code.
| leke wrote:
| This reminds me a lot of REBOL
| skybrian wrote:
| Not for me. Type annotations at API boundaries and bidirectional
| type checking is better. I don't know why people keep thinking
| Hindley-Milner is good.
___________________________________________________________________
(page generated 2026-02-21 23:00 UTC)