If you've got a #haskell identifier x and you need to figure out how to convert it to some type T, just write
_ x :: T
And hover over the underscore, and you see what type of function you need to get there.
If an appropriate function doesn't exist yet, replace the underscore with some name
f x :: T
and use the "Define ..." code action to automatically stub out a definition for f
If the definition you write for f ends up being really simple, you can then just inline it back at the use site.
Sometimes I'll nest this technique, too. If the only thing that's clear when trying to define f is, e.g. that it will look like
f = fmap _
then I'll change that to
f = fmap g
g = _
and write a definition for g, and then eventually clean it up
When stuggling with inscrutable type errors, stop struggling in your head - use the tools to get as much explicit type declaration onto the screen as possible.
Crazy type errors most often come from leaving waaaay too many types inferred. Haskell doesn't have bad error messages, what it has is really great type inference, which makes it super easy to write large expressions with no type annotations
You do this at your own risk, and you need to stop doing this if you're having trouble with it.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
There's a piece of programming advice I've been turning over in my head for some years: that a function or program or whatever unit of code ought to "do a single thing." It's always seemed like that contained a kernel of truth but was ill-phrased.
I haven't managed to fix it, but I now have in mind what I think is a fairly general special case of the sentiment - for the context of functional programming, at least. My reformulation is: Prefer to define a function as a composition of other functions where possible.
Imagine that f and g are interesting nontrivial functions. Composing them - that is, writing "h = g . f" - requires comparatively very little effort. (apologies, I wrote the compositions backwards in the drawing)
Haskell programs side effect all the time, there's no prohibition or even cultural aversion to effects. The only "effect"-related thing we really avoid is the way in many languages one uses the stack, the heap, and static memory as a myriad of little ad hoc in-process databases.
A lot of languages I look at as essentially DSLs for creating multitudes of ad hoc databases. The simplest form of a database is an IORef, which haskell has and haskellers use, but a lot of languages have dedicated syntax for IORefs (e.g. when every variable implicitly is one).
Haskellers approach a task like "map a function over a list" in a way that doesn't require instantiating a database to track the progress, and that would seem like a very convoluted rube goldberg way to solve the problem, but that doesn't come from a general aversion to effects.
For a library that wraps an HTTP API which is already decently designed and documented, *encapsulation* should *not* be the goal. Provide functions that interpret the headers and response bodies, but keep the HTTP API details in the forefront of the user's mental model.
There's a much bigger rant coming on a more general topic here, about how to write libraries that are designed to be eliminable, not libraries that "capture" a problem by forcing a lot of opinions on the user and obscuring in places that ought to be enlightening.
Designing top-down from porcelain to implementation is one cause for this problem. We can do so much better than that.