87 pointsby the_unproven9 hours ago10 comments
  • norir10 minutes ago
    I would suggest adding objective metrics. How fast is this compiler? How long is the longest fuse program? How long does it take to compile? How fast at runtime is the fuse implementation of several benchmark programs compared to semantically equivalent programs written in other languages?

    How expressive is fuse? How long are equivalent programs written in fuse/rust/scala/haskell?

    Can you show me a bug that the fuse compiler catches but some or all of the competition doesn't?

  • codebje7 hours ago
    It's nice to see a GRIN backend in the wild!

    It looks like a tidy little functional language - a small, easily grasped syntax surface and generally clear semantics. That you've got it to the point that it can compile and run proper programs is a great achievement for a solo dev project!

    The string type in the standard library isn't Unicode-aware, might be worth just noting that. Unicode support can be a big undertaking, but considering whether you'll add it later or not might affect your library design now.

    I don't really understand why you have an IO monad. The language isn't pure - `.exec()` means any function can perform IO actions no matter its type signature - so what's IO really for?

    Do `impl` additions export? What happens when two libraries add the same function name with different signatures (or just bodies!) to a type's `impl` ?

    Is currying automatic? It doesn't seem to be, but, eg, the `sum(x: i32, y: i32)` function theoretically could be called as `sum(5)` to create a closure, but this isn't a documented feature if so.

    The website's font is using ligatures, not unicode operator symbols - I'd personally find it much clearer to use a non-ligature font to show what's really there, but that's immaterial to the language.

    • the_unproven6 hours ago
      First of all thanks for all the feedback and looking into it, appreciate it!

      Yeah GRIN is a great project, it took a lot of debugging and analysis to make it compile 100% especially with monomorphization involved.

      I'll look into Unicode support, makes total sense. Didn't scope it in initially. I can fix the site ligatures too, that's a fair remark.

      > I don't really understand why you have an IO monad. The language isn't pure - `.exec()` means any function can perform IO actions no matter its type signature - so what's IO really for?

      That's a fair point, I still left a place for `.exec()` to happen as un-handled side-effect. But the preference is with using the IO monad as the stdlib is built around it, with `main() -> IO[i32]` as a type signature. As languages evolves I'm planning to build a runtime around IO execution, and build more constraints for handling strict side-effects. However for this initial stage of the language, I left it as a really simple solution.

      > Do `impl` additions export? What happens when two libraries add the same function name with different signatures (or just bodies!) to a type's `impl` ?

      For now the language doesn't support modules (libraries), I'm planning on adding it. At the moment it's a bit of undefined behavior, as overloading would occur with latest `impl` definition.

      > Is currying automatic? It doesn't seem to be, but, eg, the `sum(x: i32, y: i32)` function theoretically could be called as `sum(5)` to create a closure, but this isn't a documented feature if so.

      In the type-system it is automatic, and it successfully passes type checker as it's entirely built on top of lambda calculus. But there's an issue with codegen right now. I can def look into it and document it.

      • nxobjectan hour ago
        I’d really encourage you with Unicode support, as frustrating as of a side track it may be - I’ve had fun dogfooding my hobby languages by writing small web servers and CLI utilities. Even if it just generates part of your shell prompt!
  • deepsun29 minutes ago
    Off topic: what is the most convenient statically typed language that don't require compilation/transpilation? To run instead of bash or Python, but types are mandatory (not just hints like python).

    I know jShell has been here like 10 years, but I'm not sure it's convenient to quickly write to a file, query a url, etc.

    .ksh for Kotlin? Typescript (through Deno)? Lua?

  • Twey6 hours ago
    Love to see a real-world example of GRIN!

        trait Functor[A]:
          fun map[B](self, f: A -> B) -> Self[B];
    
    This looks a little wacky to me. I see that you can write HKTs in their η-long form and refer to them unapplied (`Functor`). But I don't understand how I would use this syntax to attach something to the trait that _doesn't_ depend on `A`. For (a silly) example,

        trait SizedFunctor[A]: Functor[A]:
          type Size;
          fun size(self) -> Size;
    
    How do I know that `List[A]::Size` is the same type as `List[B]::Size`?

    Relatedly, I want to read `Self` in there as ‘the thing that implements `Functor[A]`’ (e.g. List[A]`), but that makes `Self[B]`, instantiated, mean `List[A][B]`, which I think should be a kind error.

    • the_unprovenan hour ago
      `Self` isn't the applied type (`List[A]`), rather it's the type constructor of kind `* -> *` constrained by `Functor`. In the map example it gets desugared into:

        fun map[Self: Functor, A, B](self: Self[A], f: A -> B) -> Self[B];
      
      Since `Self` is the unapplied constructor, `Self[B]` just means `Functor[B]` e.g. `List[B]` not `List[A][B]`.

      The example you've shown with `SizedFunctor` is not currently supported, as support for associated types is not yet implemented. I got it on the roadmap tho!

      • wavemode5 minutes ago
        How do you define a trait that is itself generic? Like:

            trait ConvertTo[T]:
              fun convert(self) -> T;
        
        Seems to create a single trait ConvertTo, for a generic type with a [T] argument, rather than allowing one to define separate implementations for ConvertTo[i32], ConvertTo[String], etc.
  • helix2783 hours ago
    Superficially, I find the syntax very untuitive to read. Most languages opt to use <> for typevariables. Is there a specific reason you chose to deviate from that and use []?
    • mrkeen5 minutes ago
      I'm not sure most languages get a vote here.

      They can't even represent Fuse's Functor example, i.e.

        f: A -> B, x: F[A]
      
      so maybe they don't get any points for syntax.
    • dwb3 hours ago
      I actually can't think of any functional languages that use < > for type variables (I'm sure there's one or two, but it can't be common)
      • helix27836 minutes ago
        Depends on what you mean by functional language. I was considering main-stream languages that support some form of functional programming. So Rust, F#, C#, Kotlin, Swift, Typescript, etc
      • smt882 hours ago
        F# does, I think
    • smuffinator2 hours ago
      This is only true for C-style languages? Flix uses square brackets, as does Effekt, and Nim, as well as Python. Probably many more I'm missing. Gleam even uses normal parens.
  • nee_oo_ru5 hours ago
    Congrats on the release! Really cool to see a working GRIN backend. I'm definitely bookmarking this to give it a spin as soon as I get some spare time.
  • toplinesoftsys2 hours ago
    Great project - clean and simple syntax, pure functional language, uses GRIN framework.
  • strong-self5 hours ago
    found tree-sitter-fuse in the org, updated yesterday. is editor support next, like an lsp over the scala typechecker?
    • the_unproven5 hours ago
      Yeah the LSP support is next, my goal is to implement the language server in the fuse itself. At the moment there’s a simple formatter implementation fusefmt: https://github.com/fuselang/fuse/blob/master/examples/fusefm..., you can compile it with fuse and hook-it with your editor.

      For example I’ve this config in helix:

        [[language]]                                                                                                                       
        name = "fuse"                                                                                                                      
        scope = "source.fuse"                                                                                                              
        file-types = ["fuse"]                                                                                                              
        injection-regex = "fuse"                                                                                                           
        comment-token = "#"                                                                                                                
        indent = { tab-width = 2, unit = "  " }                                                                                            
        auto-format = true                                                                                                                 
        formatter = { command = "fusefmt" }                                                                                                
                                                                                                                                           
        [[grammar]]                                                                                                                        
        name = "fuse"                                                                                                                      
        source = { git = "https://github.com/stevanmilic/tree-sitter-fuse", rev = "eb5698f4867a4192064e54a92be280f4d2130e03" }
  • qsera7 hours ago
    I wish you took Haskell's syntax as such. Why did you mix rust and possibly other stuff with it?
    • the_unproven6 hours ago
      Haskell is a great language with a really advanced type-system, although I found its syntax hard to read at times especially as I was exploring the language at first. On the other hand I really liked how Rust syntax was defined in terms of ADTs, Traits & Methods Impls, with type signatures required for functions. Hence I wished for a similar functional language that has such write-style and type concepts, but stripping away the borrow checker, mutations, etc.
      • adastra22an hour ago
        Just as general feedback, I think your experience matches up with more software developers than the GP. Haskell is really obtuse and unreadable for those who are not accustomed to it.
  • faangguyindia6 hours ago
    i loved haskell but cross platform haskell deployment is still pain