Consider the following problem: given a list of length three of tuples (String,Int), is there a pair of elements having the same "Int" part? (For example, [("bob",5),("gertrude",3),("al",5)]
contains such a pair, but [("bob",5),("gertrude",3),("al",1)]
does not.)
This is how I would implement such a function:
import Data.List (sortBy)
import Data.Function (on)
hasPair::[(String,Int)]->Bool
hasPair = napkin . sortBy (compare `on` snd)
where napkin [(_, a),(_, b),(_, c)] | a == b = True
| b == c = True
| otherwise = False
I've used pattern matching to bind names to the "Int" part of the tuples, but I want to sort first (in order to group like members), so I've put the pattern-matching function inside a where
clause. But this brings me to my question: what's a good strategy for picking names for functions that live inside where
clauses? I want to be able to think of such names quickly. For this example, "hasPair" seems like a good choice, but it's already taken! I find that pattern comes up a lot - the natural-seeming name for a helper function is already taken by the outer function that calls it. So I have, at times, called such helper functions things like "op", "foo", and even "helper" - here I have chosen "napkin" to emphasize its use-it-once, throw-it-away nature.
So, dear Stackoverflow readers, what would you have called "napkin"? And more importantly, how do you approach this issue in general?
Functions should be named using lowercase, and words should be separated with an underscore. Functions should in addition have the grouping/module name as a prefix, to avoid name collisions between modules.
According to Clean Code you should order your methods from top to bottom, in the order they are called. So it reada like a poem.
A helper class serve the following purposes. Provides common methods which are required by multiple classes in the project. Helper methods are generally public and static so that these can be invoked independently. Each methods of a helper class should work independent of other methods of same class.
General rules for locally-scoped variable naming.
f
, k
, g
, h
for super simple local, semi-anonymous thingsgo
for (tail) recursive helpers (precedent)n
, m
, i
, j
for length and size and other numeric valuesv
for results of map lookups and other dictionary typess
and t
for strings.a:as
and x:xs
and y:ys
for lists.(a,b,c,_)
for tuple fields.These generally only apply for arguments to HOFs. For your case, I'd go with something like k
or eq3
.
Use apostrophes sparingly, for derived values.
I tend to call boolean valued functions p
for predicate. pred
, unfortunately, is already taken.
In cases like this, where the inner function is basically the same as the outer function, but with different preconditions (requiring that the list is sorted), I sometimes use the same name with a prime, e.g. hasPairs'
.
However, in this case, I would rather try to break down the problem into parts that are useful by themselves at the top level. That usually also makes naming them easier.
hasPair :: [(String, Int)] -> Bool
hasPair = hasDuplicate . map snd
hasDuplicate :: Ord a => [a] -> Bool
hasDuplicate = not . isStrictlySorted . sort
isStrictlySorted :: Ord a => [a] -> Bool
isStrictlySorted xs = and $ zipWith (<) xs (tail xs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With