-
Elementary programming
What’s the difference between this program
mapMaybe :: (a -> Maybe b) -> [a] -> Maybe [b] mapMaybe f [] = Just [] mapMaybe f (a:as) = (:) <$> f a <*> mapMaybe f as
and this one?
mapMaybe :: (a -> Maybe b) -> [a] -> Maybe [b] mapMaybe = traverse
The second one is certainly shorter, but I believe it would also be considered to be better by many Haskell programmers.
-
Why doesn't software project management handle risk better?
I work in software. A perennial bugbear of software project management is: why do so many software projects go over time? Moreover, why do they do this when so much time is spent trying to break down projects and get engineers to estimate how long the pieces will take?
The answer is simple: things take longer than we expect. And we know that we’re uncertain about our estimates when we make them, i.e. there’s actually some probability distribution over the time the task will take. So why are we surprised that things blow out and why don’t we have the tools to measure and deal with this?
-
Your orphan instances are probably fine
“Orphan” typeclass instances are instance declarations
instance T A
that occur in any module other than- the module where the class
T
is defined, or - the module where the type
A
is defined
The orthodox Haskeller viewpoint is that orphan instances are bad and you should never write them, because they can lead to incoherence. Incoherence is where we end up using two differing instances for the same type in our program. This can manifest in two unpleasant ways:
- If you actually import both instances, your program will fail to compile.
- If you do not directly import both, but rather use two modules which independently use the differing instances, you can end up with incoherent behaviour.
Both of these are pretty bad problems, in that neither of them is immediately apparent when you write the offending instance, but down the line they can cause some unsuspecting user’s code to not compile, or worse, silently misbehave.
However, these failures can only happen if is possible for an unsuspecting user to import the type and the instance separately. Moreover, in the case of compilation failure, the user must be unable to fix the source of the problem. With a little bit of care, we can use orphans quite safely so long as we can avoid the problematic cases.
- the module where the class
-
Lenses for Tree Traversals
If there’s one thing compiler writers spill a lot of ink over, it’s tree traversals. Tree traversals are infuriatingly simple conceptually, but can be a lot of boilerplate to actually write. This post covers a couple of tricks that I’ve found useful recently using tools from
lens
. -
Shark curiosity
Certain people (myself included) have a habit of reflexively attacking new arguments or ideas. Amanda Askell calls this “shark curiosity”: sharks bite things partly because their only real way of interacting with the world is their mouth, so biting is their way of finding out what something is.
Taken literally this implies a rather bleak picture (you attack things because that’s the only way you know to interact with them!?). But I think that the point is rather that to the shark, biting is not necessarily an aggressive action. For curious sharks anyway!