Currently, Elm is designed for making front end applications. I think Elm could also be a great language for other domains as well. One day Elm should be designed to be able to write applications that run outside of the browser. It’s already possible to do this because of ports, but it is not easy to do. In order to do this, there has to be internal packages that deal with things like accessing stdin and stdout, and working with the filesystem.
Here is an example of an application that could be possible:
package Example exposing ( main )
import Console
main : Program () Model Msg
main =
Console.program
{ init = init
, update = update
, subscriptions = subscriptions
}
type alias Model =
{ name : String
}
type Msg
= GotName String
init : ( Model, Cmd Msg )
init =
( { name = "" }
, Console.input "What is your nane? " GotName
)
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
case msg of
GotName name ->
( { model | name = name
, Console.print <| "Hello, " ++ name
}
subscriptions : Sub Msg
subscriptions =
Sub.none
Then we could run it like this:
$ elm run Example.elm
What is your name? Dull Bananas
Hello, Dull Bananas
If this was possible then Elm could be used for things like discord bots, cli programs, etc
What you are suggesting has been explored a lot before, but the attitude seems to be that Elm should be great at web-apps in the first place, for the sake of focus
Because of how Elm’s constraints such as immutability, we have made amazing things like the elm architecture and parsers. It would be very interesting to see what things like database querying would look like in Elm.
Ports can already do all of this stuff, but Elm should make this just a little bit easier. Functionality that is common outside of browsers like working with the filesystem should be in a package like elm/filesystem.
But just because the ability to run these types of applications isn’t a feature in Elm doesn’t mean we can’t explore new API designs by writing Elm code like the one I showed. This exploration can cause the discovery of an amazing API design that can be implemented in a different programming language.
I might make a framework for doing this type of stuff. This framework would implement things like filesystem manipulation, and it can be used to make frameworks for other stuff
Ports are exactly how this should work. Things like Html and Http are new user traps, setting up false expectations about how libraries in Elm work. A port based ecosystem will provide realistic examples others can use to make their own libraries.
I think I might make a library for Elm and Node that provides a framework for making Elm programs work outside of browsers. I’m wondering how databases would work. Is there any existing project that allows Elm to run on the back end and provides a way to work with databases from Elm?
Which is an experiment using Elm 0.16, but maybe it will still give you some ideas.
===
I am currently aiming to get the stubs for AWS DynamoDB working with my AWS code generation project. Being able to use DynamoDB is a big part of what I am aiming to be able to do with AWS services. It has an HTTP interface, so using it would be a lot like using any HTTP service.
Using platform worker and Rupert’s work on serverless it should be relatively easy to get something working on https://dapr.io/ s well. It exposes everything over HTTP.
There was lots of prior work on this in 0.18 and earlier where folks hooked into an unsupported but exposed ability to write “Kernel” (back then “Native”) JS code and FFI it directly into Elm. Someone even went so far as to try make an alternative package manager.
There were a number of people (and even companies, see Sebastien’s 2017 Elm Europe talk) who started seriously using server-side Elm.
I have spoken with a bunch of people around this topic, and explored it extensively. The end result seems to me to be that “just wrapping” these things into Elm doesn’t end up giving you a very good or nice API, or a long term maintenance experience (or even a “just do x” level of effort at that).
For example, in regards to databases, I think skimming through the readme for panosoft/elm-postgres’s approach in 0.18 might illustrate the point somewhat. Things I struggled with when trying to wrap PG myself were:
How do I map Elm types map to Postgres types?
How are foreign key constraints handled and/or modelled in Elm?
What about implicit configuration like column indexes or calculated fields?
What happens when types/tables change?
How do migrations work? How do I synchronize those with my Elm changes? Do I have to maintain multiple versions of types?
What if I change my Elm types and the DB is out of sync, or vice versa? How can I know? What should I do about it?
What about my encoders/decoders?
I believe something nicer is possible for Elm in relation to a holistic story around persisting data! I’m personally working on this notion through Lamdera but I’m sure there are many areas it could be interesting to explore something alternative to “just” wrapping things (i.e. robots in Elm is something I’d love to explore one day!).
One concrete thing I think could help the exploration you’re talking about here that’s not ideal today is a standard for how packages with JS/ports actually ship and expose that JS/ports, plus tooling to make it easier to install, include and hook-up that functionality in an Elm project.
Without this, it’s currently quite tough to compare and evaluate things that include added JS and a very manual set of work to try and use multiple together. I hope to share a proposal I’m working on with a few people here eventually but if it’s something you’re interested in please DM me!
Something I am curious about in regard to Lamdera and database persistence. If I understand it right, Lamdera saves the server-side model on every server-side update (either as a delta or a snapshot). Does this mean that all of the persistence have to be serialized, that is, there is no parallelism as per traditional database locking schemes?
You just got me curious since you mentioned it in this discussion about Elm and databases.
My reading of this is it gives clarity as to where Elm’s (and the core team’s) focus is. So when thinking about statements like this (emphasis mine):
Ports can already do all of this stuff, but Elm should make this just a little bit easier. Functionality that is common outside of browsers like working with the filesystem should be in a package like elm/filesystem.
I think well sure, they could, but that’s not the focus of Elm! So it probably won’t. I don’t think it precludes exploration in different domains, but I’m not expecting Elm to adjust course.