#The "Double bananas" ((
smell
Usual offenders:
- inside a threading macro to "protect" a fn; action: stop the threading or refactor it with
as->
((comp f g) x)
or((juxt f g) x)
or((partial f x) y)
(the three most frequent); action: unroll thecomp
/juxt
/partial
- in other cases it's worth considering giving the poor thing a name
In general I find ((f x) y z)
hard to follow, harder than (g (f x) z)
for example. In the second case the role of (f x)
is given by g
(eg (f x)
must be a predicate). In the first case the role of (f x)
is given by f alone. To recap: with (g (f x) z)
you have two sources of information to infer the nature of (f x)
(and may realize there's a glitch when the two sources are discordant), with ((f x) y z)
you only have one source of information.
Giving a name to (f x)
allows to reintroduce a second source of information (when the name is sensible).
Last, when ((f x) y z)
occurs frequently it may be worth invertigating if:
f
could accept extra args -- and turn those expressions in(f x y z)
- or a helper around f could be created -- this occurs when a lib is used in a way unforeseen by its author.