Morphir-elm: portable business logic in Elm

Elm really is a delightful language for reliable webapps and it can do so much more! I would like to introduce Morphir: an open-source project where Elm is used to build business logic that runs anywhere.

Morphir’s backbone is an intermediary representation that allows us to capture the application’s business logic in a technology agnostic manner. Using the IR as the integration point gives us a lot of flexibility in how we build, verify and run the business logic. Over the years we experimented with various frontends (Scala DSL, LINQ, …) but when we found Elm we immediately knew it was perfect for our needs so we created morphir-elm.

Morphir-elm contains an API to work with the IR and a frontend to turn Elm sources into Morphir IR. We are also getting close to completion on our Scala backend that will allow you to transpile business logic written in Elm to Scala.

Morphir is very much a work in progress but we think it has great potential. So if you are interested in language processing, code generators or logic visualization please join us and contribute!

Here are a few exciting things that happened since we open-sourced Morphir for motivation:

  • We built morphir-dapr which allows you to build an event sourced microservice in Elm and run it on Microsoft’s Dapr runtime with a single click.
  • Microsoft’s Bosque language is looking to use Morphir to integrate with other backends.
  • Morphir became a Finos project. Finos is now part of the Linux Foundation.

Let us know what you think!

Thank you

16 Likes

Well this is fascinating…

When you say business logic written in Elm, do you mean that any Elm code can be translated into Morphir? Or is it the case that you have a DSL implemented in Elm, with which you can write Elm code to build instances of that, and those can then be translated?

Looking at some of the examples, it looks like the Elm code is being translated directly. In some of the examples, I saw things like import SDK.Rule exposing (..), so there is a DSL too. Perhaps it is somewhere between the two models I described above?

I’m curious as to whether this means any Elm can be compiled to Scala, and therefore we effectively have a new Elm back-end running on the JVM. Are there limitations that mean this is not the case?

This is an area I am very interested in, because I have my own language agnostic modelling project implemented in Elm: https://package.elm-lang.org/packages/the-sett/salix/latest/

A transpiler of Elm to any other language would seem to be an implementation of Elm. After all, the official Elm is transpiled to JavaScript. Am I remembering wrong, or didn’t Evan ask in the last few months that such projects not identify as being “Elm”? This is not a negative comment on morphir-elm, which truly does sound interesting, but a requested clarification on the naming policy.

As I recall, that request was made in the context of talking about a complete fork of Elm. This doesn’t look like it is that.

I’m not clear what the criterion is that would distinguish a “complete fork” from an alternative implementation. After all, some of the “don’t call it Elm” positioning came around efforts to do things like run Elm on the backend on the server. One could conceivably do that using the existing Elm transpiler which seems like less of a fork than building a separate transpiler.

Furthermore, from a language standards standpoint, this matters because there is no Elm standard AFAIK beyond what Evan’s transpiler does. That means that it is essentially impossible for an alternative implementation to claim to be standards compliant.

As I said, this is a cool project. I just don’t know how to reconcile it with the position that the only thing that should be called Elm is the official Elm release.

Salix looks very nice. I will take a closer look when I have a chance.

Those are great questions. Let me try to answer them.

Elm is the DSL. We support all core language features and only left out things that you wouldn’t use for modeling business logic (like ports). For now we have a few other limitations like requiring type signatures on all declarations only because we don’t have the right tooling yet (no type inferencer).

The idea is that you can build “DSLs” by simply creating an API in Elm. Code generators and visualizations can match on a specific patterns in the IR if they want to generate anything specific to the given API. Rules for example might be translated to decision tables or trees in the visualization or some engine in a backend that’s optimized for rule execution.

With the few limitations above we are aiming to compile any Elm code to Scala. It’s not fully implemented in the open-source version yet but internally we generate Scala for production use. There are some edge cases where the Scala compiler needs some help to infer the right type so we will need the type inferencer before we can fix those and make the Morphir Scala generator complete.

Let me know if you have any other questions.

I agree that the naming can be confusing. It should really be called “morphir-elm-binding” or “morphir-binding-for-elm”. Morphir is made up of multiple repos:

  • morphir
  • morphir-elm
  • morphir-jvm
  • morphir-dotnet

“elm” in the name only refers to the Elm-specific tooling around Morphir.

As for being an Elm transpiler: it might sound like a nuance but we are not trying to transpile Elm into Morphir IR, we are trying to make it easy to build Morphir IR using Elm.

I hope this answers your question. Sorry for the lack of context in my original post.

1 Like

Thanks for the clarification. Using Elm as a tool for building another data structure is a very different thing from translating Elm code to a different target. Still very cool if Elm is a good way to write programs that generate Morphir.

Something else I am curious about.

In Elm, Int is really a floating point number, so you only get 53 bits of integer representation out of it. In the JVM, a long is a full 64 bits. You can see the effect of this in the repl:

> 2^53
9007199254740992 : number
> 2^53 + 1
9007199254740992 : number

I think there are also going to be differences in Char representation and Strings - UTF-8 vs UTF-16 being the defaults for JVM and most javascript engines.

When you translate to Scala, do you manage to preserve the behaviour from Elm? Or do you in fact, just use the default representations of the JVM. So a computation expressed in Elm might come out with a different result when run on the JVM?

Then there is Elms quirky arithmetic operators too…

Those are all great points. The short answer is: yes, running a computation in Elm might come out with a different answer than running it on the JVM.

Since our focus is not to run Elm on other platforms but to run Morphir on various backends they only need to be consistent with the IR’s semantics. Those semantics are still evolving but the guiding principle we used so far was to go with the representation with the least physical limitation. For example we represent integers as BigInts in Scala.

From our perspective this will only have an impact if you use Elm to test your business logic or to run it in the browser. For now we can live with those inconsistencies but in the longer term we were planning to build an interpreter for the IR which will follow the semantics of the IR.

1 Like

Thanks for that explanation - I do sometimes wish Elm had 64-bit Ints, it would be a performance hit in javascript, but whenever I think about ints really being floats it just feels so wrong…

In my mind, Elm consists of 2 parts. One is the language itself, and the other is The Elm Architecture and runtime that lets you build web applications in the language. The language itself is very minimal and really nice to use. It also has never been given a formal semantics that says there is only one correct way to interpret it. I have often thought that taking the Elm language without TEA and porting it to different platforms is an attractive proposition - well done for doing it.

Can you give us some idea of how this came about? I appreciate there may be commercial sensitivity, but if you can, what companies are behind the project? How did it come to be adopted by Finos? What use cases is it going to be put to? Are there live projects already using it?

Perhaps you are already aware of this… I saw a suggestion to look at this book on the Elm slack:

It has quite a few examples in it of using F# for domain modelling. All these examples translate well into Elm.

It isn’t quite so deep or ground breaking as the seminal “Domain-Driven Design” by Eric Evans, and a lot of what is in that book is not really touched upon. But seeing how clear and simple domain models can be produced in F#, and how these can also be executable specifications is definitely interesting. I think once translated into Elm, the examples would be even better.

I also saw this wonderful use of non-elm-format styling in one of your examples, which conveys its meaning so well:

decisionTable : Facts -> Decision
decisionTable f =
    case    Match   f.flooredAtZero     f.documentType  f.negativeInterestProtocol  f.governingLaw    of
            ----------------------------------------------------------------------------------------------
            Match   (Just True)         _               _                           _               -> Yes
            Match   (Just False)        _               _                           _               -> No
            Match   Nothing             DRV             _                           _               -> Yes
            Match   Nothing             French          _                           _               -> No
            Match   Nothing             MSFTA           _                           _               -> No
            Match   Nothing             ISDA            Applicable                  _               -> No
            Match   Nothing             ISDA            NotApplicable               England         -> Yes
            Match   Nothing             ISDA            NotApplicable               _               -> No

4 Likes

Morphir was open-sourced by Morgan Stanley. It was a slow evolution that started around 7 years ago driven by our desire to improve our software development process and our business users asking us to build more transparent systems where they can understand the behavior.

After open-sourcing multiple Finos members were interested in the project so it made sense to manage it within that organization. Inside Morgan Stanley we use it in many areas in production. I cannot get into specific details but given how generic our IR is you can imagine that it can be applied to almost any business logic. You can find a few specific examples on our github.io page.

Rules is a good example where we were able to take the fundamentally imperative nature of rules engines and turn into a pure functional representation that is more predictable without sacrificing a lot of the features. Ultimately most people use rules engines for decision tables and trees which map very nicely to FP.

Thank you for bringing up Scott Wlaschin’s work. What he is describing in his book is exactly what we are striving for. In fact we have already reached out to the F# community to see if we could build an F# frontend for Morphir as well.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.