3 ms·
> Elm certainly has a lot of boilerplate compared to Haskell This is not true based on my experiences with Elm and my knowledge of Haskell. Could you elaborat
by rtfeldman 10y ago
> Elm certainly has a lot of boilerplate compared to Haskell
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?
- wyager 10y agoHaskell has much more powerful polymorphism as provided by typeclasses and various extensions like Multi-parameter typeclasses. Haskell, more than any other production-ready language, is able to encapsulate the essence of "doing the same thing in a different context", which means you can easily write code that is reusable to a degree not imaginable in most languages. 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.
- pka 10y agoInstead of abstractly arguing over "writing generic code", here are some concrete examples I came up with when running down a random Haskell file: * 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.