1. 3

    Thanks for writing this! I recently discovered a lot of this myself, from multiple short blog posts that never quite answered the questions I had. I would’ve been in a better place with this blog post. One interesting topic that I’ve had problems with is dealing with cross-platform issues. For example, on OS-X’s default version of bash, you can’t set the auto-complete options after registering the function (e.g for when you might want whitespace optionally after the completion). The workaround sadly looks like this: https://github.com/eeue56/elm-bash-completion/blob/master/_elm_format.sh#L21

    Do you have any idea of a better solution for that problem?

    1. 1

      Thank you!

      Unfortunately I don’t have a better solution to suggest. Great work btw! If anything pops up in my mind I’ll get back to you.

    1. 4

      After looking for pro/cons in Elm and ReamsonML, my final point was that although Elm has a great pattern and offer simplicity, the interop with JS to import any external library is not fitting the need that I have.

      If I ever need to write apps without JS interoperability, then elm would be great, but for now, the ecosystem not here yet.

      1. 5

        I find this odd given that Elm targets browsers. It’s a bit like creating a native language and say: we don’t need C FFI, people can use named pipes.

        1. 6

          It’s not really that odd, when it fits into the Elm model of the world: I suggest listening to this podcast, which goes over why things in Elm are the way they are: https://elmtown.audio/99e18f41

          1. 6

            I think the vision put forth by Evan sounds like a great thing to strive for. However, as he says, these things are going to take years to happen.

            I think we are seeing the tension between building out this grand vision were everything has an ideal interface, and people using it to ship features today. It seems that recently, there has been more and more negative chatter about the limitations and issues of the language around this tension.

            Not having small patches to fix things like the issue mentioned in the linked post is probably one of larger concerns. Users of the language can make a hotfix and push it to prod in minutes, but issues in language aren’t patched for a year. I know these aren’t the same thing, and actually doing things are never as easy as they sound, but this seems to be where the creator and user are at odds.

            1. 2

              I think we are seeing the tension between building out this grand vision were everything has an ideal interface, and people using it to ship features today. It seems that recently, there has been more and more negative chatter about the limitations and issues of the language around this tension.

              I think it’s OK, and even a good thing, if the power users of a language or library or whatever are persistently frustrated by the thing, if it means a stronger and more consistent story for new and intermediate users. They’re by far the larger and more important demographic. I don’t know a lot about Elm but I get the sense that this is the case.

              1. 1

                Oh, certainly. Even having the userbase around to have these frustrations is a good thing.

                It seems there are some growing pains going from a toy language no one really uses, to one that companies are built on. I guess we have yet to see how these concerns are handled.

      1. 22

        The tl;dr for those unfamiliar with the situation:

        • In Elm, there is no FFI. Instead, you can communicate with Javascript through the use of a pub/sub system similar to making requests to an external server, known as ports.
        • The user in question was using an intentionally undocumented underyling system to write JS code that isn’t type-checked
        • In the next release of 0.19, the way this system works is changed, and restricted further. This leads user to be concerned about their continued use of Elm
        1. 3

          Mayve it’s just not clear to me, but is there an actual problem here, or just “I can’t do it exactly how I want to so I’m going to stomp my feet and threaten to leave”?

          Does the OP want something that would circumvent all of the static benefits of using Elm? Is the message passing system inadequate?

          1. 14

            is there an actual problem here

            I believe the actual problem is a communication problem: the user has read some bit and pieces, and started to be concerned about the way they are currently using Elm might not work going forward. That’s a very legitimate concern to have! However, based on what they said, their problem is actually completely solvable right now in Elm without the method they used to bypass Elm’s safety, via ports. Also, the undocumented API they used (“Native” code) led to this situation.

            Does the OP want something that would circumvent all of the static benefits of using Elm?

            My understanding is yes, that’s what they want: but in standard XY problem fashion, the real concern they have is becoming blocked by upstream bug fixes not being merged as often as they’d like. This is something we’re actively looking into improving in Elm going forward.

            Is the message passing system inadequate?

            There are some aspects of it which are inadequate, for sure. Ports require that all the code that use them be async in both Elm and JS. This can be a problem if you need sync code in your view function, for example. However, that’s entirely possible to work around.

            1. 10

              Last I checked the creator of Elm literally did not allow any libraries to be published to the central repository without his personal approval if they used the JS interop system.

              1. 5

                While technically true, this doesn’t really paint the whole picture.

                You can publish any Elm part of a package that uses ports. What you can’t do is publish the ports exposed themselves. There’s a good reason for that: to avoid name collisions on ports. So, what you do is:

                • Publish the Elm parts as a package.
                • Publish the JS parts as a package.
                • Instruct on how to connect the two.

                It’s straight-forward to do things in this manner.

                1. 3

                  Thanks for the context. While I still think it’s problematic from a social perspective to have a benevolent dictator who acts as a personal gatekeeper for what is and isn’t allowed to be published, from a technical perspective it doesn’t seem so bad.

              2. 6

                The message passing system is absolutely inadequate for some things (e.g., for replacing Math library functions, or for, as in this case, replacing the native websocket module). These can not be implemented async, and therefore not with ports.

                See this quote from the author:

                We also have some synchronous functions JS functions that we need to call that we will not rewrite in Elm. Sorry but we can’t upgrade to the official 0.19.

                For these things, you need to use JS to do it yourself, and in the latest version, there’s a whitelist restricting which people can create such JS modules. This whitelist is restricted to the elm team.

                As result, people are considering forking the compiler, or moving away entirely.

                1. 3

                  , replacing the native websocket module

                  This is not accurate: ports are perfect for replacing the websocket module. The reason why the original poster mentioned websockets is because they wanted to patch the library themselves. However, using ports instead would’ve worked just fine. That’s how the existing library is modelled, after all.

                2. 5

                  Here is the exact reason the user expressed as to why they’ll have to use a fork of either Elm or rewrite the extension they rely on:

                  Our production application relies on a fork of elm-lang/websocket which has some features and bugfixes that haven’t been merged into core yet for almost two years (https://github.com/elm-lang/websocket/pull/12, https://github.com/elm-lang/websocket/pull/18, https://github.com/elm-lang/websocket/pull/19).

                  If what I’ve read is correct, we won’t be able to switch to Elm 0.19 until Evan decides to merge those changes, which might take years judging from the fact that there has been no official reply to any PRs of that package that have been open since 2 years (https://github.com/elm-lang/websocket/pull/12).

                  It’s basically out of their hands as a user who didn’t create and doesn’t maintain the extension that their production app came to rely on so they’re already using a fork. That situation was not ideal but they had an easy path forward with the fork. They are now worried that that easy path forward has come to a dead end because the original package doesn’t seem to be maintained well enough for them to think that this will be remedied soon and they will have to do a lot of work, one way or another, to upgrade Elm ≥ 0.19. It might be an amount of work that their team will just port the app to something else entirely.

                  1. 3

                    There are libraries like elm-websockets the OP had to fork and use their forked version because their bug fix PRs have not been merged in 2 years. So the issue of not having releases for years (instead working on the next major release only it seems) and now planning to even disallow this work around for the lack of releases.

                1. 5

                  Last couple of weeks I’ve been working on improving some of the Elm tooling that exists. In particular, I’ve added these things:

                  • elm-bash-completion which gives you auto-complete for Elm tools in your bash/zsh terminals
                  • elm-help which is a tool to give you information about a particular package or your local application from the command line
                  • elm-documentation-parser, which is a “mostly works” library for getting documentation from Elm files that matches the docs produced by the --docs flag in the elm-make binary
                  1. 7

                    For fun(!) I wanted to make a client for MPD with Elm and display:grid. It now works more-or-less and was easy enough to do, but I’m not really happy with the default websocket library from Elm. Maybe there is one with a more explicit connection state? For this week to finish it I want to make the design presentable.

                    1. 4

                      What in particular are you looking for in controlling the connection state? The idea behind the websocket library is mostly built around the idea that you shouldn’t need to worry about handling the connecting or how messages are sent. You can use the low level functions to put together an explicit model of the state if that’s what you need

                      1. 2

                        I would like to know the state of the connection, so I can display that. Or not show certain parts of the GUI when there is no connection. The current magic reconnects by the high-level module can take quite a while, with the build in exponential backoff (and reloading does not force the establishing of a new connection, somehow).

                        The low level functions are really rather low level :) Guess I’ll have to dig in them anyway…

                        1. 2

                          Indeed, for those types of situations you are best off using the low level stuff directly. If you need a hand, join the Elm Slack – there’s lots of people who can help!

                    1. 2

                      I’m improving elm-debug-decoders, a tool designed to help you visually iterate on your decoders.

                      1. 5

                        “a mere 450k” - that’s still a ton of JavaScript to load! I’m a JavaScript-first developer for the most part, but I just don’t understand how people have totally given up on making things small and efficient. Elm is probably great on its own, but I’m not buying it as a replacement at this point. 22k -> 55k LOC is ridiculous.

                        1. 14

                          That’s prior to minification. Luckily for you, the focus of 0.19 is on improving the SPA story: reducing data loaded from the server, DCE, etc.

                          1. 2

                            Good to know!

                        1. 3

                          We’re improving swagger-elm for work. Adding generation of http tasks so that you don’t have to write any of the network code on the client any more!

                          1. 3

                            While reading these announcements and considering most of the developments to be rather smart, some of the updates (not necessarily in this one, earlier ones had more “short cuts”) I wonder whether some features geared towards making things easier come at a high price for readability and getting into the language.

                            Is there experience on this? Do people consider it a lot harder or read and understand Rust code compared to Go or Python (when they know them and have worked with them of course)?

                            I understand that expressiveness of course comes with some price, but I am wondering on how well reading Rust code from other people works, when it remains somewhat idiomatic.

                            1. 6

                              I write Go and Rust pretty much daily and I don’t really experience any amount of trouble reading code in either one. But I’ve been using both languages for many years now.

                              1. 8

                                I wonder whether some features geared towards making things easier come at a high price for readability and getting into the language.

                                It depends on the feature, really. For example, I wrote this code recently:

                                match item {
                                    &Item::Module { ref name, ref docs } => {
                                

                                once https://github.com/rust-lang/rust/issues/42640 is implemented, this code will instead be

                                match item {
                                    Item::Module { name, docs } => {
                                

                                much, much easier to read. This is what I actually wrote, but the compiler yelled at me, so I had to add in the &s and refs to make it work. This is geared at usability, but definitely makes reading and getting into it easier.

                                ? is another recent one that I think you’re thinking of, maybe; I was skeptical at first but it’s really grown on me. I find it easier to read than the old try!.

                                As always, YMMV.

                                1. 3

                                  Coming from the language design of Elm, which takes readability and ease of understanding as a priority, I found the types in Rust in particular to be very counter-productive. For example, imagine you want to split a string. Simple, right? It should just be something like split : String -> String -> List String. Not so in Rust. In Rust, you have to first figure out this type which looks this: <'a, P>(&'a self, pat: P) -> Split<'a, P>. Figuring out what ', & and <> are quite a big wall to run into early on. For this reason, I would not personally recommend Rust unless you specifically have an interest in it or need a language like it for work. I would definitely argue that

                                  Context: I have done a pretty large amount of Haskell and have written a decent of Idris. Types are not a scary thing to me, but when I run into types which are harder to read than they should be, it really frustrates me. That being said, Rust does do some really cool things, and complicated syntax can help complicated features exist. Different languages have different purposes :)

                                  1. 14

                                    I appreciate what elm does, but the Elm type signature and the Rust type signature express different things.

                                    Elm describes: “given a String and a String to split, return a List of new Strings”.

                                    We could easily have fn split(&self, pattern: &str) -> Vec<String>. But that would mean that you immediately heap allocate a number of strings. (That’s directly readable from the signature)

                                    Rusts split signature describes something very different: “Given a String and a pattern, return slices into the original string. These slices cannot be used after the original String is removed from memory.”

                                    Generics aren’t the weirdest thing in the world, so are references. I’m a bit surprised that languages that have a notion of them are now seen as weird.

                                    Finally, you make it seem like Strings are the easiest in the world and their APIs all have to be dead simple. The opposite is true: Strings are the nastiest data type. Their APIs might reflect that.

                                    I give you that the split signature isn’t the easiest to read at first, that’s why it comes with a lot of examples, which use very easily. It reads very clearly once you know the lingo.

                                    1. 5

                                      I appreciate and understand the difference, and I also understand the goal. But please remember that I am answering a question from a perspective “How easy was Rust to learn?”, and not “Is Rust a useful language?”. In a world where you have to care about memory, this kind of representation is important. But that does not make is an easy to learn language.

                                      I appreciate what elm does, but the Elm type signature and the Rust type signature express different things.

                                      The point of the split comparison isn’t quite “this is what Elm does, this is what Rust does” – I was rather saying “This is what I would expect, but instead the type signature looks like that”. In particular, there’s several layers of complexity:

                                      • The new Split type
                                      • & syntax
                                      • 'a syntax
                                      • <'a, P> syntax

                                      This is why the split type signature is confusing and offputting to newcomers. It does not work nor look as newcomers expect it to.

                                      We could easily have fn split(&self, pattern: &str) -> Vec. But that would mean that you immediately heap allocate a number of strings. (That’s directly readable from the signature)

                                      It is entirely feasible to have a lazy data structure in the form of an iterator. It does not need to be a custom Split type. It would be easier to understand with that small change – introducing new types instead of using familiar names can have a counter-productive effect on aiding learners.

                                      I give you that the split signature isn’t the easiest to read at first, that’s why it comes with a lot of examples, which use very easily.

                                      To you, as a user of Rust, it is very easy. To others coming to your language, it is not. The first place I look at when figuring out a function is the types if it has it. The examples come only to clarify the knowledge I gained from the type. split in Rust does not give me sufficient knowledge from the type signature to feel comfortable reading the rest of the document. Of course, given enough examples, I could understand how to use it, but for me, having clear type signatures is more important than having lots of examples. This is why I say that I could not recommend Rust as a language that is easy to pick up, unless you need it at work. Obviously, polyglots and people with an interest in language design will try it out anyway. And they should! It does some very different and interesting things. Please don’t take this as me saying “Rust is bad, don’t use it” :)

                                      1. 10

                                        Yet, you don’t address my most important point: the comparison doesn’t fit, we have opted for a vastly more powerful implementation at the cost of a harder type signature.

                                        The whole rest of the String docs mostly has very with plain signatures.

                                        I find your insistence that having all syntactic options of Rust in one signature still a little weird, you will always find functions like that in any language. There’s certainly a problem for people that absolutely want to grok the signature before use, but then, well - that’s the moment where those people must go out and learn them. There’s not much you can do. It’s not even like these are fringe concepts of the language, you will be able to reuse them for years to come :).

                                        (By the way, due to the issue of rust not having anonymous return types, it is indeed not possible to avoid the custom Split type)

                                        I do know the problems of newcomers quite well, I make part of my income with training Rust and founded the largest training group. split is only shortly among them.

                                        I didn’t find your post dismissive, just picking a local maximum and hitting very hard on it also isn’t very useful criticism. Also, your conclusion doesn’t seem quite right: almost every user of Rust currently is a hobbyist, and many find it very interesting that they can finally encode those things in their signatures.

                                        1. 2

                                          Yet, you don’t address my most important point: the comparison doesn’t fit, we have opted for a vastly more powerful implementation at the cost of a harder type signature.

                                          I address this with this:

                                          The point of the split comparison isn’t quite “this is what Elm does, this is what Rust does” – I was rather saying “This is what I would expect, but instead the type signature looks like that”.

                                          Please re-read my comment carefully. You are coming across fairly hostile, and I don’t want a flame war – like I’ve said, I am not saying that Rust is a bad language.

                                          I find your insistence that having all syntactic options of Rust in one signature still a little weird, you will always find functions like that in any language

                                          I’d love if you could point out any of such complexity in a language other than Rust, Haskell, Idris or Purescript. For example, if “any” is to be taken to be true, could you find one in Elm or Mypy or Typescript or even Java? There is a restricted set of symbols that you need to learn for each of those, and they tend to come it later, after you have written your first production code.

                                          There’s certainly a problem for people that absolutely want to grok the signature before use, but then, well - that’s the moment where those people must go out and learn them

                                          Here’s the funny thing about using symbols in type signatures: they are literally ungooglable. It’s hard to learn what 'a means, because you cannot Google it easily.

                                          By the way, due to the issue of rust not having anonymous return types, it is indeed not possible to avoid the custom Split type

                                          This is another area where Rust trades power for readability and accessibility. Languages can and should be improved constantly.

                                          I do know the problems of newcomers quite well, I make part of my income with training Rust and founded the largest training group. split is only shortly among them.

                                          If that is true, then I am very surprised that you yourself say in another comment.

                                          I’m a little confused by this, as the docs come with a ton of examples and usage is really easy. Yet people get hung up on the type signature, which is admittedly “all in” at first, but easy to read once you are a little in.

                                          If your job is literally training people to understand Rust, then I assume you also take time to learn why they see things that way. I am telling you that examples alone are not enough for me: perhaps some documentation that explains why split is the way it is is needed. Just showing what it does is not enough.

                                          I didn’t find your post dismissive, just picking a local maximum and hitting very hard on it also isn’t very useful criticism

                                          It’s interesting, as I do find your post dismissive and hostile. I’m simply giving my opinion on the language design of Rust from the perspective of how easy it is to learn. That was the original question. I’m answering it from the perspective of someone who works with a language that is easy to learn.

                                          Edit: I originally phrased part in a negative manner, due to bad English skills. Rephrased to be less negative

                                          1. 4

                                            Your original comment said this:

                                            but when I run into types which are harder to read than they should be

                                            And you (seemed to) back this up by a false equivalence.

                                            This is very different than saying, “these are things that are hard for a newcomer to learn,” which would be entirely reasonable. I think you shifted more towards this position in your follow up comments, but it was not at all clear from your first comment. Your first comment makes it seem like Rust introduces needless complexity into its type signature, instead of acknowledging the tradeoffs that skade pointed out.

                                            In general, I do agree with you that the type signature is hard to read. I personally think it’s hard to read more because of the conceptual burden rather than specific pieces of syntax though, which makes it a much easier pill to swallow. The conceptual burden is there for a very good reason. Nevertheless, I do take this into account when designing library APIs. Failing that, I rely on writing clear documentation with examples to counteract the complexity in the type signature.

                                            1. 4

                                              That’s fair enough, I guess what I meant was that is harder to read than I, as the learned, expected it to be, rather than it being harder than it needs to be. I did not meant the complication is fully unwarranted – some of it is, and Rust represents some things in types few other languages do.

                                              1. 4

                                                Agreed. A big part of teaching Rust is managing expectations.

                                    2. 2

                                      As a beginner thinking “split” would be an easy, I tried reading the docs (i.e., parsing the type) and gave up. For things like these I bruteforced my way through the compiler errors or asked in #rust-beginners on irc.mozilla.org.

                                      1. 6

                                        I’m a little confused by this, as the docs come with a ton of examples and usage is really easy.

                                        https://doc.rust-lang.org/std/string/struct.String.html#examples-52

                                        Yet people get hung up on the type signature, which is admittedly “all in” at first, but easy to read once you are a little in.

                                  1. 2

                                    Is there some more info on who this is for? I filled it in, but would love to know a bit more about what it’s for. P.S: a real great way to make sure lots of people don’t give up half way through is to show a progress bar. I almost gave up on the 4th page before realizing it was the last.

                                    1. 4

                                      I released the initial public version of elm-sketch-importer, a tool for exporting your Sketch files into Elm. It’s a work in progress, but I’m pretty happy with how it’s shaping up. I will be converting it to use my elm-html-in-elm AST for Html, which will allow it to be generate straight HTML for free. Check it out if you’re using Elm and Sketch, or even just Sketch :)

                                      I’ve recently changed jobs to work at a company called Schibsted. I’ve been getting familiar with Ramda and compile-to-JS languages which aren’t Elm. Out of Flow, TypeScript and ReasonML/BuckleScript, I am most fond of Typescript. They’ve really put a lot of love into it, and the tooling is amazing. ReasonML is very immature, and the error messages are sub-par. I found them harder to use than GHC’s errors. Flow required a lot of set up, and I felt tired by the time I had actually got into writing code.

                                      1. 10

                                        Server-side rendering — sending HTML with the initial response

                                        Tree shaking — trimming out unused code (usually called dead code elimination or DCE)

                                        Code splitting — cutting up code into smaller chunks for better caching

                                        Lazy loading — only sending the code chunks needed for a particular page

                                        Okay, Elm has gotten my interest again. Looking forward to these being available :-)

                                        1. 3

                                          Server side rendering has existed in Elm for at least a year, FWIW.

                                          1. 1

                                            I quoted the whole block, which was my bad. I most meant the last three.

                                        1. 1

                                          Hmm, why is this tagged unix? I assumed that OPy referred to ops-related things. This is a post about an alternative Python compiler.

                                          1. 5

                                            Because the “Oil Shell” is a new unix shell being built. Read the homepage.

                                          1. 4

                                            I’m doing an Elm Q&A tonight with fellow Elm contributor Luke Westby. The rest of the week, not too much planned.

                                            1. 1

                                              It bothers me that Elm’s type system allows any of these to compile. I’ve never seen a language that strictly guarantees a lack of undefined behavior - even Haskell has runtime errors, and the ability to throw a runtime exception. I’d like to see someone write a language where it really is the case that all compiled programs are guaranteed not to crash, and any other behavior is a specification or implementation bug.

                                              1. 7

                                                First off, please don’t conflate runtime errors and undefined behavior. Errors in Haskell and most other languages are pretty well-defined in what they do.

                                                Wanting “guaranteed crash-free programs” is understandable, but the issue is they’re super tedious to write, and inevitably any program of size just has some variety of Result/Either threaded through that behaves like exceptions except with no stack trace. The other thing with the zero-exceptions ideal is it forces you to be defensive about things that need no defense. Example: regexes, like the article mentions. I shouldn’t have to write a runtime check to verify the compile-time condition of a correct regex. Same for indexing an array of known length: if I have code like let arr = [1, 2, 3] Just first = arr !! 0 in first the compiler should not force me to provide an exhaustive match on arr !! 0.

                                                Also note that even in Elm’s limited case, errorlessness forces them into some really questionable design decisions. For example, what’s n / 0? Well, for floats it’s infinity (fine) but for ints it’s 0 (super not fine!) Of course they did this because it would be incredibly tedious to have to unpack a Maybe for each integer division. I would rather have my program crash than be subtly broken by this silliness.

                                                1. 0

                                                  In actuality, how often have you used n / 0 to actually crash the program and appreciated it? You can consider division by 0 to be a logic error - and therefore, it’s something that should be caught by tests, not by the compiler.

                                                  1. 1

                                                    Would be great if someone replied instead of just downvoting. One thing I like lobsters is that people don’t downvote just because they disagree, and instead comment to further the understand of the community.

                                                2. 1

                                                  That is the case with Elm. All the the things I’m talking about here are implementation bugs, except for the single case of Debug.crash. It’s actually nice to be able to rely on your frontend code. With Elm, if my code compiles, it works. I don’t have to worry about it crashing at runtime – and that’s not something to turn your nose at.

                                                1. 8

                                                  Neat. It’s nice to have some features like pattern matching in C-likes. It’s also very awesome to have a language spec for a language like this. For same reason, C– has ended up being used a lot in schools for teaching compilers. It would be great to include ML-like features in compiler courses for C-style languages, like pattern matching and unions.

                                                  Sidenote:

                                                  Mae Myrddin yn yr enw Cymraeg am Merlin. Ti'n dweud e fel “Muh-rh-th-in” mewn Saesneg! Mae dd yn swndo mor fel “th” galed mewn Cymraeg. Nagw e'n swndo fel d.

                                                  Myrddin’s the Welsh name for a Merlin character. You pronounce it as “Muh-rh-th-in”. The double d is actually a letter, which sounds more like a hard th in English. It doesn’t sound anything like d.

                                                  1. 3

                                                    Cool, I’ve been looking for implementations of pattern matching compilers.

                                                    https://github.com/oridb/mc/blob/master/mi/match.c

                                                    If that’s it, it doesn’t look too long at 839 lines. As far as I understand, compiling to decision trees results in the fastest but largest code, and backtracking automata is the opposite tradeoff.

                                                    https://hal.inria.fr/inria-00000763 (page 2)

                                                    People say the decision tree requires exponential space in the number of patterns but I don’t quite get that?

                                                    Also checking for pattern matching exhaustiveness is apparently NP-complete?

                                                    http://trevorjim.com/finally--pattern-matching/

                                                    1. 4

                                                      Yes, that’s it. Note that it doesn’t try to be especially clever about optimizing things. Still, I’ve found that in practice, either the matches are often shallow, with the wildcards (captures) clustered near the end. So far, it hasn’t mattered too much, although I also haven’t put so much work into generating fast code.

                                                      1. 3

                                                        People say the decision tree requires exponential space in the number of patterns but I don’t quite get that?

                                                        If there are N things to test, a decision tree might need height up to N to make decisions. A complete height-N binary tree has 2^N nodes. In practice not every decision path will be full-height, but depending on how you construct the tree, in the worst case you can still end up with size roughly on that order. One bit of intuition for why is that you can have exponentially many duplicate tests: somewhere down the tree, it might turn out that 6 of the 8 branches need to make exactly the same test, so this test is duplicated 6 times. Ways to avoid this include heuristics to ensure the tests needed by more paths end up further up the tree and therefore not duplicated, and explicit sharing between branches, i.e. a decision DAG rather than a proper decision tree.

                                                        1. 1

                                                          OK yeah, so then the way I think about it is that the branching factor of the tree is related to the number of patterns/cases… but the height of the tree is related to the number of variables tested (the depth of the patterns).

                                                          The height is the thing that is exponential, so it’s the number of variables tested. You might need to test a single variable against like 20 things, but that doesn’t make it exponential.

                                                          I guess it just doesn’t seem like a big deal in practice to be exponential this way. Am I wrong? Are there some examples from real code where just doing the naive thing results in a lot of bloat? I feel the patterns are commonly at most 3 or 4 levels deep, but I don’t have tons of experience with ML.

                                                          I guess this could answered with some program analysis…

                                                      2. 3

                                                        Re. Your note about the pronunciation. Bengali has 5 (I think) d-like sounds. I wonder if your “dd” is then like the bengali dh “ধ”. This is pronounced like this

                                                        1. 3

                                                          Hmm, not quite. The dd doesn’t sound very much like d at all. At least not to my Welsh ears. Here’s a north Wales pronunciation -> https://youtu.be/nnH33183y2M?t=17

                                                          1. 2

                                                            Wikipedia’s Welsh phonology page groups it as a voiced dental fricative, like Greek δ. Your sample doesn’t sound identical to how I would pronounce Greek δ, but much closer than an English ’d' in either case.

                                                            1. 3

                                                              Yep, agreed, that is closer. When I make that noise, I push my tongue up behind my teeth, leaving a gap between the roof of my mouth and my tongue, and then sharply exhale, allowing my tongue to vibrate. I don’t know that helps much, but hopefully it does! It’s also important to note that the noise of a word in Welsh puts a lot of pressure on the first syllable - as dd is at the end in Myrddin, then it has a much softer sound than if you pronounce the letter alone.

                                                              1. 1

                                                                That does actually sort of help explain why it sounds a little different, I think. I pronounce Greek δ as you describe, except with the tongue pressing against the gap between slightly parted upper and lower teeth. Whereas it sounds like your tongue is against the upper teeth, not against a gap between upper and lower? The linked Wikipedia article on voiced dental fricative briefly mentions an “interdental” variant (which is what I use). When I attempt both varieties, the interdental version sounds “harder” to me, i.e. if there’s a spectrum from the softer th in “think” to the harder th in “that”, both are on the harder end of the spectrum, but interdental is further there. Maybe?

                                                                Getting even more off-topic in this off-topic thread, but the first time I heard Welsh on a train, I thought it was Swedish. I’m not 100% sure why, because there is no actual linguistic relationship. The closest I can figure out by listening to some stuff on YouTube is that there’s a certain upwards intonation at the end of words like “bydd” that is very similar to an upwards intonation in the Swedish tonal system on words that end in “-iet” (example here). There is something else about the phonology and/or intonation that really minds me of Swedish though (specifically Swedish, not Danish… I lived in Denmark for years and Welsh sounds nothing like that).

                                                      1. 10

                                                        Blog posts! I’ve actually written 4 blog posts in the last few days. I’ve also taken some of my old, unpublished blog posts and written them in my new style. My latest is on how I implemeneted json-to-elm, if anyone is interested. I’m trying to blog about things that I end up answering on slack, or giving talks about a lot. So that includes problems with Elm, things people find hard to do with Elm, experimental projects, etc. My next blog posts will probably be about server-side Elm, or build tools. It depends if I get more motivation, but I have a blog post written for both right now.

                                                        I’m also working some more on elm-fuse, but no big progress updates other than the rewrite I got done last week!

                                                        1. 2

                                                          Awesome! Can’t wait to read about server-side Elm and build tools.

                                                        1. 1

                                                          I wonder if they are going to try to do some kind of ML module thing.

                                                          1. 2

                                                            I personally find ML-style modules to be a stricter, but stronger abstraction for libraries than typeclasses.

                                                            Also, I don’t quite understand the final point in the post: needing to look up viewSomething to understand viewCity etc. Isn’t the whole point of writing modular code that you don’t have to really care about what the implementation details are? If you need to understand the implementation entirely (as you might for a rendering function), having typeclasses vs modules vs some other abstraction mechanism becomes mostly irrelevant.

                                                            1. 1

                                                              Yeah, maybe I didn’t explain that last bit so well. I think my point was that you can already write things in a type-class style (by ensuring each record has a contract of record -> Html msg), but that that style does not give you much extra in terms of readability nor in boilerplate. Boilerplate is the problem that most people are facing with Elm right now - and the introducing of typeclasses may be either harmful or overkill for that problem

                                                            2. 2

                                                              It’s been discussed, and actually effect-modules have a syntax inspired by OCaml’s parameterised modules.

                                                            1. 7

                                                              For what it’s worth, the lack of Typeclasses is why I gave up on Elm. For an otherwise fairly usable language, it was just too inconvenient.

                                                              Purescript is very promising. Unfortunately, I think the learning curve may be too high for many people. Elm has a simple and straightforward UI system that you’re basically required to use, whereas purescript gives you some options, and the one I found first (Halogen) uses concepts that are well beyond the experience of your average programmer. Elm’s nested tree system is relatively very approachable.

                                                              1. 5

                                                                Do you have some example code of where you found it too difficult to go without typeclasses? In the majority of cases I come across, it is usually solvable in a different style than the person is used to. A lot of people come from languages like Haskell, and expect Elm to have all the features Haskell does – and therefore end up trying to solve problems in a Haskell manner, which can be very frustrating once you realize that Elm doesn’t have typeclasses. I’d be very interested in seeing what you came up against :)

                                                                1. 3

                                                                  it is usually solvable in a different style than the person is used to.

                                                                  All of these languages are Turing Complete. It’s always doable, but not always convenient.

                                                                  The most prominent example I remember is wanting sets and maps with keys of arbitrary types.

                                                                  1. 5

                                                                    I actually discuss that exact problem in the blog post, including linking to the solution, a package called elm-all-dict which I wrote a long, long time ago and still maintain.

                                                                    It’s pretty convenient - just use EveryDict anywhere where you might’ve put a normal Dict. There’s a small hit to performance, but nothing you would notice unless you’re processing info from Hubble or something.

                                                                    1. 1

                                                                      So you’re basically emulating typeclasses by explicitly passing the relevant functions. Like I said, that works, but completely eliminates any of the convenience or safety afforded by unique global typeclasses. It also doesn’t really generalize well to things more complicated than, say, Ord or Hashable. Soon you have to start passing around giant objects full of lots of functions, and now you’re just doing typeclasses by hand.

                                                                      1. 3

                                                                        Actually, EveryDict doesn’t require you to pass in relevant functions. AllDict does, but EveryDict hashes things for you. So no, not quite.

                                                                        But also: the point is that typeclasses, for most things, are a nice-to-have. If you write your code in a different manner, then it’s not a need-to-have. Very few people have these problems in production - I’m among the people who have written the most Elm and have rarely thought “oh typeclasses would help me write this view in a better way”. Other things are more important to increasing Elm adoption and ease of use over typeclasses.

                                                                        So I’m not trying to say that typeclasses don’t have a place - they definitely do, and they should be added in. But they need a lot of thinking about first, and there are other things to address first. Hence why the yet

                                                              1. 3

                                                                I I quite like the approach of ppx_deriving_yojson, where you specify a type and add annotations how JSON should be deserialized from and also generates serializers to do the reverse. All this in a type-safe way which avoids the problem with the misordered fields in the record.

                                                                I could imagine something like this could be useful in Elm, considering that JSON in Elm is far more important than it is in OCaml, where this is implemented using two libraries and some macro.

                                                                1. 2

                                                                  Yeah, this is very similar to the golang alternative. Just tag the fields in a struct as json and specify an incoming json name, and you’re good to go. In my experience, it doesn’t handle up so well when you need to decode a complex type (for example, recursive data structures that have optional fields), but it’s a lot better than what Elm has now.

                                                                  The alternative I suggested isn’t really a good alternative - it’s one that solves one particular problem of the JSON API which new users rarely think about. My point of this blog post was to hopefully kick start this conversation and get people suggesting and providing alternatives, because I have pushed for automatic decoders/encoders long enough alone :)