See [0] for a good example of well-commented but idiomatic Haskell (a snippet from the popular Megaparsec parser library), which includes things like:
data ParsecT e s m a
ParsecT e s m a is a parser with
custom data component of error e,
stream type s, underlying monad m
and return type a.
Admitted, that is a monad transformer, but one-character type variables with human-readable docs are both good for newcomers as well as low-friction for people who are used to the library in question.(Strawman alert.) It is significantly more work to parse (ha) something like
ExceptT fooException (StateT fooWorldState underlyingMonad) a
when compared to ExceptT e (StateT s m) a
[0]: https://hackage.haskell.org/package/megaparsec-5.2.0/docs/Te...Of course, Edward Kmett had a story about winding up with his code telling him `i m a s t a b u`...
m >>= k = ...
In a somewhat more esoteric vein, I love the use of w for comonads: the rationale is apparently that it looks like an upside-down m.> Of course, Edward Kmett had a story about winding up with his code telling him `i m a s t a b u`...
Is that an indexed lens ... parameterized over a monadic type? I'd like a link to the video/article.
> I love the use of w for comonads: the rationale is apparently that it looks like an upside-down m.
That's my understanding, yeah.
> Is that an indexed lens ... parameterized over a monadic type?
Presumably further parameterized by the focus, the source structure, the target structure, the focus again, the transformed focus, and some third structure.
> I'd like a link to the video/article.
Me too :-P I see a couple references in a google search but I'm not sure where I first heard it.
The second tells me nothing - how is this intended to be used? What scope is it intended to be used in? Why was it created? Where does it fit in the program flow?
In other words, my thesis is that if you aren't familiar with State, both State s and State fooAppStateType are fairly opaque.
In any case, most of the time one works with a specialized instance, for instance, one might have something likr
newtype AppState a =
AppState {
runAppState ::
ReaderT Config
(StateT AppState IO)
a
}
and then there's no problem at all.If you're trying to understand how a library works when you're not very fluent in the language, that's what the documentation is there for! Any good library (and this is an area where's lots of room for improvement) should document the types it uses and the idioms that it lends itself to, and as one accrues experience, the whole "learning to see common patterns" takes over. The great thing about a helpful compiler of the Rust/Haskell ilk is that you make fewer mistakes in between (modulo occasionally horrific error messages).
And I'm willing to vouch for this not being expert (ha) blindness - I have only recently become comfortable enough with these things to talk about them.