Ellie – An Elm Live Editor
humblespark.com
humblespark.com
Elm made me enjoy frontend development again. Can't recommend it enough.
"All content created with Ellie is released in the public domain (CC0)."
Are they claiming that any program written with Ellie is in the public domain?
(edit) I've emailed to ask their intent. I'll post an update if I get a reply.
I let him know that those terms would make me very reluctant to use Ellie for anything, even open source code, since the ability to apply an open source license requires that I have a copyright. I suggested that they putting a very visible statement of what they're doing on the page.
But I found the documentation to be of a really low quality, and I believe good docs are the most important thing for any language aiming for developers' adoption.
At least the docs on elm-lang.org weren't any good - maybe there's some alternative projects out there?
let rant_ = [
I just wanted to have a thin non-breakable space (U+202F) and haven't found anything about actual syntax in the "syntax" document, nor anywhere around that. Syntax docs is just a bunch of examples with a short notes - a quick cheatsheet at best.
Then I wanted to browse Html package contents and see what's the difference between beginnerProgram and program and what else do they have in stock (with Haskell I always had good idea of module's contents by reading docs on Hackage), but the docstrings were nearly meaningless, not even listing the arguments. "Read about The Elm Architecture", really? I just came from that document (and they only cover beginnerProgram basics), hoping a module docs would give me better idea.
] in sorryAbout rant_ -- I had eventually figured it all out, but was quite disappointed.
Spacemacs + elm layer + elm-hot-reload. If you have two screens (or enough resolution) you can have something similar to this app with all the power of a great editor. (Sure it could be emacs + evil or Vi(m) instead)
Format seems to be in Alpha, doesn't limit line length?
It's tricky with Elm because it's written in Haskell, so compilation etc. takes long time in the browser, but this is quite nice. Should definitely push to replace /try with this.
im a huge fan of the Elm broswer. and have been using Elm with atom along with elm reactor. That has worked adequately. Most difficulties are ironed out by making sure the Elm code compiles. Then at least all the parts are fitting together.
But maybe I have written code that compiles, but doesn't express what I am wanting.
It's a bit much in the morning.
.components_header_Header {
background-color: #000080;
}It's a shame that all that hits me in the face with Elm code examples lately is awkward style conventions. Why do they have to be so user hostile?
Trailing brace on the next line even for this?
type alias Model =
{ counter : Int
}
Instead of: type alias Model = { counter: Int }
Comma first, when trailing comma is so much more intuitive, why this? Html.program
{ view = view
, update = update
, subscriptions = \_ -> Sub.none
, init = ( model, Cmd.none )
}
instead of: Html.program {
view = view,
update = update,
subscriptions = \_ -> Sub.none,
init = ( model, Cmd.none ),
}
(... which makes for better diffs too). And weird bracket soup for DOM: div []
[ div [] [ button [ onClick Increment ] [ text "+" ] ]
, div [] [ text <| toString model.counter ]
, div [] [ button [ onClick Decrement ] [ text "-" ] ]
]
... when it's going to be translated to DOM anyway, why not? <div>
<div><button onClick={increment}>+</button></div>
<div>{toString model.counter}</div>
<div><button onClick={decrement}>-</button></div>
</div>
This is needlessly distracting from all the things that are nice about Elm.The HTML functions in Elm tend to take two parameters: a list of attribute values and a list of child DOM nodes. Again, this is all code. The list values you specify are again just functions that get evaluated.
It's a little less obvious because of the syntax style of Elm, but it does let you write the function calls out in such a way that they express that tree structure.
It bears repeating: your Elm div example, at the top level, is a single function call with the first parameter '[]' being an empty list (because you aren't assigning the node any attributes like a DOM id or CSS class) and the second parameter being a list that'll be made up of the DOM nodes that result from each of the function calls within it.
This was one of the biggest mental roadblocks I had to get past when learning Elm. Just forget the idea of HTML and think instead of DOM tree-of-nodes and a lot falls into place. The 'view' function you write will return a DOM tree data structure which is then taken and applied to the browser document. You pass in your model as a parameter to that function and then other functions you call within this DOM-generating code you've written will use that data to return different DOM contents depending on it.
That is why I used JSX as a counterexample. Basically I'm questioning Elm's choice to stick with the raw dom-creation-function-style vs adopting a JSX equivalent.
Elm is a functional language, and you build the desired DOM structure with functions. Why should it be any other way?
JSx looks sort of like HTML, but HTML isn't even the target here, just DOM nodes.
Lisp-style 'S-expression' syntax for describing documents never took off. We have to take something from that - it seems the vast majority of developers don't enjoy that syntax, irrelevant of how 'simple' its just-functions nature makes it.
JSX also 'targets DOM nodes', but I don't see what that has to do with anything.
The closer correspondence between how JSX looks, what you see in your browser DevTools, and how it seems that most developers prefer to mentally model documents ... is where the win comes from IMO.
The reality is the vast majority of React code I see uses JSX, even though it's optional. It's been hugely successful in React world and I don't think that should be ignored by Elm.
div []
[ div [] [ button [ onClick Increment ] [ text "+" ] ]
, div [] [ text <| toString model.counter ]
, div [] [ button [ onClick Decrement ] [ text "-" ] ]
]
JSX isn't the only syntax that took off, there are for example indentation based syntaxes for HTML, theoretically: div
div
button onClick: Increment
text "+"
div
text <| toString model.counter
div
button onClick: Decrement
text "-"
already much nicer (and if it was all wrapped in parens it wouldn't make much of a difference).Given that Elm is "just" for making HTML apps, this does seem like something the language should focus on.
It turns out that it's less work to always have delimiters than it will be to have to add them anyways to disambiguate.
I love Elm and think it or something very close to it should become way more mainstream, but I do find its bracket-heavy DOM syntax off-putting in comparison.
EDIT: That said, I do agree with the leading commas in laying out models as opposed to the trailing. Scanning the models of an Elm file is far faster than, say, a JS file, subjectively at least.
Thus, no structural, recursive syntax for document editing has "taken off".
Word processing is still done in Microsoft Word by most of the planet. HTML e-mails are written in some WYSIWYG client program. Web forums use variations on markdown (with raw HTML only as an escape hatch).
People do work with *ML by hand, but largely reluctantly.
If you do have to roll up your sleeves and work with the serialized syntax, you're far better off it its is S-expresions.
> If you do have to roll up your sleeves and work with the serialized syntax, you're far better off it its is S-expresions.
Convince the masses, because they don't seem to agree.
Html.program {
view = view,
update = update,
subscriptions = \_ -> Sub.none,
init = ( model, Cmd.none ),
}
Because the parse would expect something to come after that last comma. And thus you would have the last line being special and different.Also, it is much easier to look at this
Html.program
{ view = view
, update = update
, subscriptions = \_ -> Sub.none
, init = ( model, Cmd.none )
}
And see if all of the commas are actually present ;)> Also, it is much easier to look at this [...] and see if all the commas are actually present.
ESLint can trivially lint that you haven't missed a comma (including the final trailing comma). The style guide/ESLint config I use (Airbnb's) enforces trailing commas. If ESLint can do it, Elm should be able to.
[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Well, Elm is not trying to be JS, it's trying to be better, and there's really no reason to need trailing commas. I'd even argue that it argue it leaves a message of mixed intent "did the author want to continue the list?" and needlessly enables duplicate styles for the same one thing.
Which languages are you referring to? Almost every language I'm aware of allows trailing commas.
C, C++, Java, Python, C#, Javascript (somewhat), Ruby, Objective-C, Perl, PHP, Elixir, Rust, and Go all allow trailing commas.
Except you've now traded the last line being special for the first line being special.
The main difference is that the Elm "bracket soup" is just a composition of functions and is subject to some type checking by the compiler. Elm view code as such can easily be restructured and refactored using the simple laws of function composition, which are very powerful, especially in combination with a strict type system.
Also there are some things about Elm's DOM style in particular that are especially awkward, compared to other function-style dom creation syntax [0], like the [ ] everywhere.
> The main difference is that the Elm "bracket soup" is just a composition of functions
So is the JSX counterexample I gave, (it de-sugars to function calls), which is why elmx [1] can exist, and seems like an improvement to me.
[0] https://github.com/hyperhype/hyperscript [1] https://github.com/pzavolinsky/elmx
> Refactoring your views with the same ease that you do with your normal code and with a compiler to watch your back is liberating
I have this experience with JSX (which I didn't have with string template libs), and I also don't see that an Elm equivalent like elmx would take anything away from that experience in Elm.
The result won't be understood by elm-format. Compiler errors will exist at the level of Elm, not elmx. It's something extra that has to be learned by any other developer trying to work on the code -- and they'll still have to understand the pure Elm code that the elmx compiles to as well. Plus it has limitations like not being able to nest code interpolations.
No I'm not, and I'm tired of 'the familiarity argument'.
> elmx feels like it just complicates the view code with virtually no benefit.
See my other comments in this thread - I don't agree - JSX being more closely related to the DOM you're building is a significant benefit.
Also empirically in React land, JSX is vastly more popular than not using it.
> The result won't be understood by elm-format.
If ESLint can understand JSX, then elm-format can understand elmx.
> It's something extra that has to be learned by any other developer trying to work on the code
That dev already knows DOM (or will have to do so via their devtools) if they're a front-end dev.
(And React seems to have proven that's not an issue).
> they'll still have to understand the pure Elm code that the elmx compiles to as well
I don't experience this in React. I never think about the 'create dom'-ish JS calls it's translating to.
> Plus it has limitations like not being able to nest code interpolations.
Unless I misunderstand you, JSX can absolutely do this.
> Non-recursive interpolation: currently Elm code interpolated between { and } is not recursive (i.e. is a regular grammar not a CFG). This means that you cannot include curly brackets inside curly brackets.
This is of course just a limitation of the implementation, not the idea.
The last one is because all html in Elm are just regular Elm functions. This means no special syntax to manipulate html, and you have the power of all of Elm at your fingertips, without shoehorning it into a new syntax. [1]
Honestly some quite silly arguments...
[0] You can read some of the benefits on the style here https://github.com/avh4/elm-format/blob/master/README.md
[1] Explained a bit down the page https://guide.elm-lang.org/architecture/user_input/buttons.h...
>What if you want to change the first item of a list?
Html.program
{ view = view
, update = update
}
to Html.program
{ view = newView
, update = update
}
Leading comma vs allow a non-terminating comma both leads to the same diff of just the one line.I mean, there are quite a bunch of languages that don't support non-terminating commas, which is really a bit of parsing that hides intent.
Other than that, bashing a language for having the convention (that is not forced by the language but by... convention) is quite ridiculous. The HTML comment is a valid point to raise, but there is quite a good reason for having it be native Elm, which brings a ton more benefits than having JSX'esgue syntax.
[ 1
, 2
, 3
]
to [ 0
, 1
, 2
, 3
]
diff - [ 1
+ [ 0
+ , 1
, 2
, 3
]
> Other than that, bashing a language for having the convention (that is not forced by the language but by... convention) is quite ridiculous.It is forced slightly by the language as trailing commas are currently invalid syntax (though this is on the roadmap to be fixed). It's also more than just a convention, as it is explicitly recommended in the official Elm docs.
Putting commas on the left-hand side means they're out of your way once and for all.
The versioning diff argument is much less interesting. Most people don't care about that.
Regarding HTML, you may want to look at elmx [0]. It accomplishes exactly what you described.
In a similar vein...
https://marketplace.visualstudio.com/items?itemName=Rubymani...
Really I think it's just the stage of adoption that the language is in. It really is cutting-edge in that way and everyone is figuring out the best way to do things. It's early, early days.
In my current project, I've used templating to solve this. I ended up with a huge Elm main program that was 90% case-statements to call the appropriate update, view or other functions (eg- passing JSON data from the back-end server to the appropriate places). I got cranky enough with it that I made a templates version of it using the doT.js library and a script.
Now I can specify the subscreens I want in my application in a JSON file and have a script take that and my Elm code template and spit out a perfectly readable main.elm file which then gets compiled as normal. It's actually turned out really well for my purposes.
I am sure one gets used to it after some time, but prepending lines with comma, just because it makes it easier to add new lines is so so ugly and takes away from the main intent for newcomers.
This is akin to starting each sentence in English with a dot!
Else every language would be annoying to write, especially a lisp.
People can live with different tab lengths. I'm not so sure every project needs to be bike-shedding about it, though.
I alluded a bit to it in another comment here, but I'm not entirely convinced that the "you shouldn't write components" is a good design target overall vs. just being a necessity because of the limitations of Elm the language right now.
It probably hinges on what you mean by 'component'. When I say 'component', I mean a bit of UI I'm planning to reuse across multiple pages, where there might be some private model, where I would not want the internals of that model duplicated across and polluting otherwise clean page models.
Here is an example that comes to mind: I have common functionality across pages in my app where I want to let the user edit a database field.
To do this, the user can select the list of fields from a drop-down or they can type the field name into a search box, with choices being displayed as they type in real-time; they can then click on a choice and edit that field.
To submit the edit, they click an 'Update' button.
Now, this functionality is shared across different pages in my app. None of these pages should, IMHO, necessarily have to care about the intermediate states of the field-list as it is auto-completing. I simply want a function I can call from any view like this:
renderChoiceThingy : List FieldChoices -> ChoiceThingyModel -> msg -> Html msg renderChoiceThingy fieldsToPickFrom model actionOnSubmit = ....
Not only might I want multiple instances of this same thing across many pages, but I'll also want multiple instances of it on the same page sometimes. For example, let the end-user build up a list of changes and then submit them all in a batch or cancel them all at once.
Without treating this like a self-contained unit, I'm now duplicating model bits in all my pages that use this function. So it's nice to wrap that control up into a module, with its' own 'update' and 'view' and have appropriate parameters to allow the proper message types to work.
Another example (not one I've implemented); say you have an interactive colour picker, that you can click on an icon to exapnd, select the colour you want by changing sliders interactively, then have the picker disappear and the page know what colour you've selected. To me, the containing page shouldn't care about all that slider stuff and all the messaging and updating that goes on, just to draw the picker.
Would love to hear other Elm devs thoughts on this. These are the kinds of examples I don't see directly addressed when people say "don't write components". Though I suspect, having not used other 'component' frameworks like React, that people might generally mean something slightly different to what I'm thinking when they say "no components". Really interested to find out what others think about this.
Indents let the reader know the current line is a continuation.
Comma-first also creates worse diffs than (enforced) trailing comma.