* 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.