Live data from Hacker News

Elm in Production: 25K Lines Later

charukiewi.cz

231–240 of 278 posts

Re: Elm in Production: 25K Lines Later

#231

After doing a couple of contracts on Elm projects for several months, and returning now back to a React-Redux stack project, I cannot emphasize enough how much better working with Elm is. In every single aspect. I just wish that it will get mainstream as soon as possible. His article is spot on, and agrees with what I've seen, and most others that used Elm. Just look it up.

I am more interested in the details that just this blank statement that everything is better. After trying Elm several times we failed to implement even basic things in it that we could do in React/Redux easily. For an average JS developer Elm is totally alien tech compare to React or Angular. For Haskell programmers Elm is pretty appealing because of the familiar syntax and type system, but the intersection of Haske…

If you get stuck on anything, come tell us about it on Slack. We can help you get unstuck! The majority of Elm users come from JS -- so while the syntax is different, it should not to be too hard to pick up. This is one of the reasons that Elm has avoided complex features from Haskell. It's really not very much like Haskell beyond syntax. Redux is very much like Elm, seeing as it is an implementation of the Elm Architecture.

Re: Elm in Production: 25K Lines Later

#232
post #17
post #8

First: > Elm has an incredibly powerful type system Near the end of the article: >Want to decode some JSON? Hard, especially if the JSON is heavily nested and it must be decoded to custom types defined in your application. IMHO the lack of typeclasses/traits is really hurting Elm. Take haskell f.e. {-# LANGUAGE DeriveGeneric #-} import GHC.Generics data Person = Person { name :: Text , age :: Int } deriving (Generic,…

If you want a powerful type system (i.e. Haskell), but the benefits of Elm, Miso is a project that implements the Elm Architecture in Haskell. It obviously has typeclasses, and can encode / decode JSON on the frontend using GHC.Generics quite well. https://github.com/dmjio/miso

And GHCJS is quite good these days as well.

Re: Elm in Production: 25K Lines Later

#233
post #161
post #152

Earlier quoted context omitted.

I don't know Haskell but how is laziness related to FP?

The only way I can think to relate them is (a) FP tends to highlight the importance of value-semantics over all others, (b) non-termination is an effect, (c) FP also, subsequent to a, tends to emphasize control of side effects, (d) in a terminating lambda calculus all evaluation strategies are confluent/equal under the value-semantics, thus (e) laziness is particularly _available_ in a FP language.

Attempt at translation from CS-speak:

Laziness matters less in a FP language because if we consider non-termination an effect (impure), all pure functions should behave exactly the same regardless of whether they're "lazy" or not (plus in FP sameness is defined as same values, due to "value-semantics" - unlike OO where every object has a unique identity, different from all others) because in the absence of side-effects order of evaluation is not important.

Of course reality is different, and laziness has very visible and important effects when Haskell programs run on today's computers :)

Re: Elm in Production: 25K Lines Later

#234

Earlier quoted context omitted.

Here is what people are comparing it to, in terms of difficulty: json.loads('foo.json') I spent 3 days about 6 months ago, off and on, trying to figure out json decoding in elm, and gave up on the language entirely. It wasn't a matter of simply specifying types. The syntax is confusing the compiler isn't any help. I had very little difficulty working with anything else in Elm, so I think there is a lot of work to be…

Elm's primary selling point is "no runtime exceptions". The subheader on Elm's homepage even says this[1]: Generate JavaScript with great performance and no runtime exceptions. Type safety doesn't come for free. If you want to build an application that doesn't have runtime exceptions, you have to specify what external data should look like, how to translate that data into a native datatype, and what to do if that exp…

Elm's type system will not catch this bug at compile time, it will still be a runtime exception, unless you're saying Elm's compiler does an HTTP call to that endpoint to verify that the interface matches the response object??

The only difference in your example probably is that Elm will force you to handle the case where your interface doesn't match the response object (missing field, in this case). But nothing in Elm forces you to handle it well, so if the programmer forgot to handle it well in TypeScript, they will do the same in Elm, and the end result will be the exact same: a runtime failure.

Re: Elm in Production: 25K Lines Later

#235

Earlier quoted context omitted.

> As soon as you have side-effects (an IO is a side-effect) you can through your assumptions about "strict conformation to definition" out of the window Again, you are unfortunately quite wrong. You do not understand the IO Monad. No IO is ever performed in any code written inside the IO monad (unless using unsafePerformIO). Please take some time to fully understand Haskell before criticising it so openly on a public…

So, you're telling me that Haskell never does any output and never reads any input. In this case (an only in this case) would it strictly conform to FP definition.

Indeed Haskell the language doesn't do any IO. Instead, it creates a tuple containing

* a description of the action to execute (e.g. read line from STDIN)

* a function that will take the result of the previous action (e.g. the line) and return the next action to execute (e.g. writeLine)

  [readLine, \line -> writeLine(line)]
This main action is just a description, the runtime itself takes it, does the actual IO described in the first part of this tuple, evaluates the second (function) part of the tuple with the result of that IO, receives a new pair of action/function, does the action's IO part, evaluates the new function and so on until it gets a nil (end of the "linked list" so to speak)

You could imagine this as a linked list of actions, where the "link" is actually a pure function you call with the result of execution the first part to get the rest of the list (or nil to terminate). This is still pure because the action itself doesn't do anything. If you return an action from a function, it doesn't actually execute, its just a value to be interpreted.

Does that make a real difference or is it just theoretical "purity"? Yes it does make a difference.

For example, if you create two action values, you haven't actually run anything yet, just created descriptions of actions. You could put them in a list and create an action description that will tell the runtime to run them in parallel, for example using: https://hackage.haskell.org/package/parallel-io-0.3.3/docs/C... ... or in sequence https://hackage.haskell.org/package/base-4.10.0.0/docs/Prelu...

For refactoring, it means that you can still take functions that return actions and substitute them with their values, e.g. if you have

  readItems 0 = return []
  readItems n = do
    x 
you could pull (readItems 3) out of main!

  read3Items = readItems 3
  
  main :: IO
    items 
and everything is exactly the same, since all you've pulled out is a description of an action. Equational reasoning (you can substitute an equation with its result) still works - which is great for refactoring!

Re: Elm in Production: 25K Lines Later

#236
post #90

Earlier quoted context omitted.

It's obvious that the concept of monad can either be explained in 5-10 lines in both JavaScript and Haskell, or neither. Which are you claiming?

It's not obvious. I'm claiming that: - the concept of monad can be explained in 5-10 lines in Javascript (demonstrable) - the concept of a monad requires multiple years and tens of tutorials in Haskell (also demonstrable)

I just want to reiterate: point 1 is totally false. That description you linked is incredibly incorrect, captures almost nothing of the spirit of what a monad is, and is somewhat disingenuous.

Lots of people get excited about "monads" and then rush out to write tutorials to try and capture whatever mental model they're using. These mental models may arrive at correct results most of the time, but they're often not really transferrable to another human.

Learn You A Haskell takes a different approach, in which you arrive at creating monads because you naturally derive them as a way to deal with the tedium of functional code w/out such mechanisms.

"Monad tutorials" are becoming much less frequent now that such approaches are offered. Everyone just says, "Go read this chapter or two of this freely available book and you're good to go."

You know, just like any major feature in javascript.

Re: Elm in Production: 25K Lines Later

#237

Earlier quoted context omitted.

Here is what people are comparing it to, in terms of difficulty: json.loads('foo.json') I spent 3 days about 6 months ago, off and on, trying to figure out json decoding in elm, and gave up on the language entirely. It wasn't a matter of simply specifying types. The syntax is confusing the compiler isn't any help. I had very little difficulty working with anything else in Elm, so I think there is a lot of work to be…

json.loads('foo.json') (what is that? python?) requires that the json matches your types exactelly. This, at least for me, is rarely the case. And yes, it is. Here is code from my own project: Json.map3 HintTemplate (Json.field "ID" Json.int) (Json.field "Text" Json.string) (Json.field "Image" Json.string) Where HintTemplate is a record type containing an integer id, a string text and a image url. What about this is…

That's reasonably similar to handwritten haskell json parsing:

    instance FromJson HintTemplate where
        parseJson = withObject $ \o ->
           HintTemplate
              o .: "ID"
              o .: "Text"
              o .:  "Image"
I wrote and > out but there is a definition like map3:

    liftA3 f a b = f  a  b
This works for all applicatives, though. Is it normal for elm libraries to copy paste code like the map3 definition?

Re: Elm in Production: 25K Lines Later

#238
post #234

Earlier quoted context omitted.

Elm's primary selling point is "no runtime exceptions". The subheader on Elm's homepage even says this[1]: Generate JavaScript with great performance and no runtime exceptions. Type safety doesn't come for free. If you want to build an application that doesn't have runtime exceptions, you have to specify what external data should look like, how to translate that data into a native datatype, and what to do if that exp…

Elm's type system will not catch this bug at compile time, it will still be a runtime exception, unless you're saying Elm's compiler does an HTTP call to that endpoint to verify that the interface matches the response object?? The only difference in your example probably is that Elm will force you to handle the case where your interface doesn't match the response object (missing field, in this case). But nothing in E…

> Elm's type system will not catch this bug at compile time

This is completely false. Elm's type system will force you to handle the decoding failure at compile time. The `decodeString` function has the following type:

    decodeString : Decoder a -> String -> Result String a
Which means that when you call `decodeString`, it will return a Result containing either the decoded value or a String describing the error.

This is not a "runtime failure". This is the compiler forcing you to explicitly spell out what you want to happen the case of a decoding problem. The difference between Typescript and Elm is that Typescript's compiler will happily let your program crash when this type of issue occurs, whereas Elm's compiler won't.

Re: Elm in Production: 25K Lines Later

#239

Earlier quoted context omitted.

This is trivial to avoid with a linter (which is a good idea to use anyway with JavaScript). For Flow, there's an eslint plugin that allows you to raise an error on the use of any weak type, such as `any` [1]. I'd be very surprised if the same doesn't exist for TypeScript. 1. https://github.com/gajus/eslint-plugin-flowtype#eslint-plugi...

Cool! Does it enforce third-party libraries as well? A thing that typescript and/or flow doesn't support, is JSON. What if a JSON object doesn't match the type? This can cause sneaky bugs later :/ I'm not saying that typescript/flow is bad. Whenever I have to use node.js, I end up using typescript. But I've been bitten several times by the fact that typescript isn't as strict as Elm forces things to be.

> Cool! Does it enforce third-party libraries as well?

Yes, as long as you lint those libraries, too.

> A thing that typescript and/or flow doesn't support, is JSON. What if a JSON object doesn't match the type?

That's why you do runtime validations of your incoming JSON if you feel like you can't trust the data (and if it's an external API, you probably can't). How is this different from Elm?

> But I've been bitten several times by the fact that typescript isn't as strict as Elm forces things to be

In my experience with Flow, between the Flow analyzer and accompanying linter, you can make it just about as strict as you want with respect to types. The main thing you'll miss (as discussed elsewhere) is that unlike Elm, there's no way to guarantee referential transparency with JS and Flow.

Re: Elm in Production: 25K Lines Later

#240
post #234

Earlier quoted context omitted.

Elm's type system will not catch this bug at compile time, it will still be a runtime exception, unless you're saying Elm's compiler does an HTTP call to that endpoint to verify that the interface matches the response object?? The only difference in your example probably is that Elm will force you to handle the case where your interface doesn't match the response object (missing field, in this case). But nothing in E…

> Elm's type system will not catch this bug at compile time This is completely false. Elm's type system will force you to handle the decoding failure at compile time. The `decodeString` function has the following type: decodeString : Decoder a -> String -> Result String a Which means that when you call `decodeString`, it will return a Result containing either the decoded value or a String describing the error. This i…

You're just rewording what I said. The coder can simply ignore that string or make it empty, which can lead to a runtime failure if another module depends on a value being returned (think a runtime failure from a non-exhaustive pattern match). If they were a lazy coder in TypeScript, they'll be lazy in Elm (:

So, no, what I said is not "completely false"

Post reply on HN