Hacker News new | past | comments | ask | show | jobs | submit login
The Hamler Programming Language (hamler-lang.org)
133 points by rossng on June 11, 2020 | hide | past | favorite | 44 comments



Looks really interesting. I‘ve always admired the erlang community but writing slang always felt like something was missing and having recently dove into Haskell this looks like it has a lot of potential.

Few questions: 1) how stable is hamler? I’m eager to dive in but know I don’t have time to work through frequent language bugs if I’m going to do anything real with it.

2) A good reference, which I didn’t see in the doc and having a hard time articulating my self would be a comparison of Hamler vs Haskell erlang FFI support? https://hackage.haskell.org/package/erlang

3) What are the key differences between Hamler And Haskell (sort of a continuation of the last question)?


>1) how stable is hamler? I’m eager to dive in but know I don’t have time to work through frequent language bugs if I’m going to do anything real with it.

Still a work in progress

>3) What are the key differences between Hamler And Haskell (sort of a continuation of the last question)?

Think of the differences between Haskell and Purescript, because while the syntax is Haskell-like, most of the infrastructure is based on PureScript


This definitely seems like a best of both worlds type situation.


> What are the key differences between Hamler And Haskell

Targeting BEAM is pretty huge!


Ha yes! That sounds great but theoretically the version of Haskell currently intercepted by ghc could be compiled to beam similar to how there is a compiler for the javaVM.

What is fundamentally different about Hamler and Haskell?


Purescript is strict, so I'd imagine Hamler is too.


Added to my Erlang resources gist. Amazing how many languages are now available for the BEAM.

https://gist.github.com/macintux/6349828#alternative-languag...


At the risk of tooting my own horn, I've got one more for ya: https://otpcl.github.io


Thanks, added.


> Amazing how many languages are now available for the BEAM.

There's hardly anything like it!


Nice list. Just an update... `Thinking in Erlang` no longer exists


Thanks, removed. Probably a few broken links on there by now.


I'm relatively ignorant about this, but a common refrain I've heard repeated about strongly typed languages targeting the BEAM is that typing of messages is [hard / an ongoing research problem / impossible]. Can anyone comment on whether that is true and what that says about this language?


I'm not an expert either, but I think it basically comes down to 3 things:

1. typing messages - this is basically trivial, you can either create a specific ADT for all the acceptable messages, or you can type messages in a "general" way as `(string, list[any])` or similar (provided that your language supports `any`)

2. typing of acceptable messages - that's way harder, as you need to model state in the typesystem - imagine "does this variable represent an open or closed file handle" and then updating that as the code calls `open`, `read` and `close` appropriately... Rust's borrowing is a simple example of that as well

3. regardless of (2), you need to figure out what to do with unacceptable messages - in a dynamically typed language like Erlang, I imagine those can happen anytime - but then even dynamic languages need to deal with "this process doesn't accept this message" so ...

this is the only mention that I found in Hamler's documentation about messages, so I'm guessing they're using the ADT approach mentioned in (1)

https://github.com/hamler-lang/documentation/blob/master/gui...


> 2. typing of acceptable messages - that's way harder, as you need to model state in the typesystem - imagine "does this variable represent an open or closed file handle" and then updating that as the code calls `open`, `read` and `close` appropriately...

I think that would be a good use case for Dependent Types.


It honestly depends on your use-case. For heterogeneous systems that may run different versions of your Erlang software, strictly-typed messages are not that great, because you can't really ensure that all your systems are running the same version of the code that accepts messages. (This is why in Protobuf3, everything is optional, for instance)

If you are a smaller organisation than, say, Google, ensuring compatibility between your systems is easier, so that's still doable.

For in-VM messaging, since all types are accessible and enforceable, it's easier to have a common contract amongst all your actors since the risk isn't the same.


It can be done with a sufficiently expressive type system, I think.

One area I'm experimenting is is a library I co-wrote[0] in Haskell that uses the type system to attach a "version" tag to a type so that your code knows what version of a record you're looking at (and also so that you can upgrade/downgrade records between versions if you need that as well).

[0] https://hackage.haskell.org/package/DataVersion-0.1.0.0/docs...


This seems like the right approach... We store persistent data in DBMSes, which have a schema defining the layout of our data, and use versioned migrations to upgrade the data. All new data either has optional parameters with default values for all new properties, or the app has to be taken offline and all versions upgraded at the same time to migrate.

It seems reasonable to reflect this practice in all state based data representations within a language, not just in an external system. Is the reason this isn't done as a first class citizen of language design because it's too much work to write migrators for every data structure change?


> because it's too much work to write migrators for every data structure change?

I think that might be one factor. And writing that migration by hand would be another source of potential errors to sneak into your program without some static analysis to ensure the streams in your program are handling the version of the data specified.

Making it easier to write migrators and have your whole program verified automatically has been working well for me.


It's not that typing is hard/impossible, it is that typing messages make certain operations in BEAM impossible (dynamic code upgrades).

From the fingers of Robert Virding itself: https://elixirforum.com/t/how-hard-would-it-be-to-have-a-str...


Dynamic code upgrades? Can you explain what that is and why a type system will prevent that from happening?


In erlang (in the BEAM vm to be more precise) you can update an application while it is running, it was a requirement for the language, even though these days it is a lot less common, its still possible.

The way that the BEAM does that it is that it store the old and the current version of the module, any new calls made will call the functions exported in the new module, but any process already running will call the functions of the old module.

But how do you handle types in a system like that, where the type of a message can change at runtime? There's no guarantees that your valid types that the compiler just approved will be valid at runtime...

learnyousomeerlang has this quote about rolling upgrades:

"We're getting into one of the most complex parts of OTP, difficult to comprehend and get right, on top of being time consuming. In fact, if you can avoid the whole procedure (which will be called relup from now on) and do simple rolling upgrades by restarting VMs and booting new applications, I would recommend you do so. Relups should be one of these 'do or die' tools. Something you use when you have few more choices."

https://learnyousomeerlang.com/relups#the-hiccups-of-appups-...


It indeed is difficult to combine static typing, and actors that can receive messages from any other actor. "Session typing" is a way of handling this, but I've yet to see an implementation that isn't overly complex.

Type-checking messages on the sending side is straightforward: just use a generic PID/actor type of some sort. So for example (using Inko [1] syntax here):

    let child: Process!(String) = process.spawn {
      ...
    }

    child.send('hello')
Handling this on the receiving end is more tricky, as a receive could happen anywhere at any time. Imagine somewhere deep down you have a method like this:

    def foo {
      process.receive
    }
How would the compiler know what type `process.receive` is supposed to return? What if you want not just a string, but a specific list of strings?

I'd say that for most languages the best approach is to use some kind of "Any" type for messages, and rely on some form of pattern matching to figure out what you're dealing with. This has the downside of not providing compile-time safety, but it might be good enough. For example, in Inko (this is a new addition not yet released) you would do something like this:

    match(process.receive) {
      'start' -> { start_the_thing }
      'stop' -> { stop_the_thing }
      else -> { oops }
    }
[1]: https://inko-lang.org/


Yes, it's super difficult to limit the receiving end. If you use a mailbox type, it quickly needs to handle basically all shapes of data. Session types or similar are needed to get all guarantees we want but are super complicated. I looked at this in my MSc thesis "Singly typed actors in Agda": http://studentarbeten.chalmers.se/publication/256251-singly-...


This would be interesting to check out, but in my experience with using Erlang for a IIoT type application, gradual typing with dialyzer is sufficient for large code bases. We also employed property-based testing to a limited degree.

The complicated part of applications that Erlang is well suited for is reasoning about the state of the entire application based on the state of the various concurrent processes. Perhaps I'm missing something, but I don't think that's something that stronger type systems can really help more than what you would get from other tools like concolic testing, TLA models, etc.


I'm curious why this isn't a backend for the existing PureScript compiler, since the front-end seems to be copy-paste identical?


We really appreciate all the work Purescript has done. Hamler is still in the early stage of development. We have made some changes on the front-end to introduce some built-in Erlang data structures and syntax sugars, and we are planning on making more changes in the front-end. The initial plan of the language was for the company’s internal use and later we decided to make it open-source hoping to communicate better with the community.


I agree. And only mentioning PureScript as the "base" in one place on the webpage is not giving PureScript enough credit.


Interesting to see this kind of work coming out of China.

> The founding team of EMQ hails from Huawei, IBM, Amazon, and Apple with years of experience and a deep understanding of the industry.

https://www.emqx.io/about


Another options for typed actors is Akka for Scala and Java: https://doc.akka.io/docs/akka/current/typed/actors.html


Always fun to see compilers written in Haskell!

And always good to see people targeting BEAM.


Looks cool! Is this meant for use in embedded applications? I couldn’t find info about compile targets and performance on resource constrained systems (in other words, can I target an Arduino?)


Since it compiles to BEAM, I would assume it's meant for use anywhere Erlang (or Elixir or any other BEAM language) would be appropriate.


How does it compare to PureScript used with purerl? https://github.com/purerl/purerl


It leverages PureScript's CoreFn IR.


And purerl does not? It mentions it in its readme. And in practice, do you know what advantages it gives over the purerl's approach?


Has anyone tried writing a distributed app with Hamler ? It would be great to see an example that shows off the inbuilt messaging of erlang and the static typing of Haskell.


It compares itself to Erlang. How does it compare with Elixir?


This looks cool! The BEAM absolutely needs languages on it with a solid functional type system.

Curious to see what interacting with the OTP with its callbacks actually looks like.


A new family member! It's good to see BEAM is getting traction.

The documentation seem to be work in progress. I wonder how to type processes/genservers. But generally, it seems to be a good fit, since most Erlang code is already pretty functional (immutable, no variables, etc).


The logo is so similar to Haskell's ...


It's a Haskell style language for the Erlang VM.


the name seems to be a mush of Haskell and Erlang :p


Haskell on OTP? Yes, please!

What's it like to debug?




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: