Elm certainly has a lot of boilerplate compared to Haskell, but that might not be a fair comparison as they don't really have a shared use case. Elm ends up with considerably less, in my opinion, than something like React/Redux.
Elm certainly has a lot of boilerplate compared to Haskell, but that might not be a fair comparison as they don't really have a shared use case. Elm ends up with considerably less, in my opinion, than something like React/Redux.
This is not true based on my experiences with Elm and my knowledge of Haskell.
Could you elaborate on why you are certain of this?
For example, the expression "fold", from Data.Foldable, is capable of doing anything from concatenating all the strings in a set to adding up all the probability distributions in a sequence. This is a contrived example, but it's super useful in practice. It's hard to imagine all the code reuse you can get, especially as a library author, without using Haskell for a while.
The most obvious cases are Ord and Eq, where things like maps and sets can contain any orderable type, rather than just a few types like String and Int.
* Thing.map :: (a -> b) -> Thing a -> Thing b instead of deriving Functor (or Applicative, Monad, Generic, ...)
* showThing :: Thing -> String, readThing :: String -> Maybe Thing instead of deriving Show/Read
* decodeThing :: Json.Value -> Maybe Thing, encodeThing :: Thing -> Json.Value instead of deriving From/ToJSON
* lenses definitions instead of makeLenses ''Type
* things like
update (Event childEvent) model -> let (m, fx) = Child.update childEvent model.child in ({ model | child = m }, Fx.map Event fx)
instead of using lenses* append :: (a -> a -> a) -> (b -> b -> b) -> (a, b) -> (a, b) -> (a, b) instead of reusing the Monoid instance on tuples
* toDyn :: (a -> TypeName) -> a -> Dynamic, fromDyn :: (a -> TypeName) -> Dynamic -> Maybe a instead of deriving Typeable
* things like type StateLogger st = { log :: [st], current :: st } and then writing StateLogger.map, StateLogger.return, StateLogger.andThen, StateLogger.modify, StateLogger.tell instead of just type StateLogger = WriterT [st] (State st) and getting all of that for free... not only that, but now you can use lenses for manipulating a deeply nested state as well, because guess what, Control.Lens.Zoom is written generically
And those are just the possible, but cumbersome things. There's stuff that's impossible to do:
* free monad custom DSLs
* GADT datatypes for typesafe request/response communication
* existential quantification in ADTs
Now this is very down-to-earth get-things-done Haskell code. All these things are there because they make the code simpler, easier to understand and eliminate repetition.