Что делает хорошее имя для вспомогательной функции?

Рассмотрим следующую задачу: задан ли список длин трех кортежей (String, Int), существует ли пара элементов, имеющих одну и ту же часть "Int"? (Например, [("bob",5),("gertrude",3),("al",5)] содержит такую ​​пару, но [("bob",5),("gertrude",3),("al",1)] нет.)

Вот как я мог бы реализовать такую ​​функцию:

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

Я использовал сопоставление образцов для привязки имен к части "Int" кортежей, но сначала хочу сортировать (чтобы группировать как члены), поэтому я поместил функцию сопоставления паттернов внутри where. Но это подводит меня к моему вопросу: какая хорошая стратегия для выбора имен для функций, которые живут внутри предложений where? Я хочу быть в состоянии думать о таких именах быстро. Для этого примера "hasPair" кажется хорошим выбором, но он уже принят! Я нахожу, что шаблон появляется много - естественно-кажущееся имя вспомогательной функции уже используется внешней функцией, которая ее вызывает. Поэтому я иногда называл такие вспомогательные функции такими вещами, как "op", "foo" и даже "helper" - здесь я выбрал "салфетку", чтобы подчеркнуть ее характер использования, один раз, выбросить.

Итак, дорогие читатели Stackoverflow, что бы вы назвали "салфеткой"? И что еще более важно, как вы относитесь к этой проблеме в целом?

Ответ 1

Общие правила для именования переменных локального диапазона.

  • f, k, g, h для супер простых локальных, полу-анонимных вещей
  • go для (хвост) рекурсивных помощников (прецедент)
  • n, m, i, j для длины и размера и других числовых значений
  • v для результатов поиска по карте и других типов словарей
  • s и t для строк.
  • a:as и x:xs и y:ys для списков.
  • (a,b,c,_) для кортежей.

Они обычно применяются только для аргументов HOF. Для вашего случая я бы пошел с чем-то вроде k или eq3.

Используйте апострофы экономно, для производных значений.

Ответ 2

Я склонен вызывать логические функции p для предиката. pred, к сожалению, уже принято.

Ответ 3

В таких случаях, когда внутренняя функция в основном такая же, как внешняя функция, но с разными предварительными условиями (требующими сортировки списка), я иногда использую одно и то же имя с простым, например. hasPairs'.

Однако в этом случае я скорее попытаюсь разбить проблему на части, которые полезны сами по себе на верхнем уровне. Это обычно также упрощает их именование.

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)

Ответ 4

Моя стратегия довольно тщательно следует за предложениями:

  • Если для этого есть очевидное имя, используйте это.
  • Используйте go, если это "рабочий" или в противном случае очень похожи по отношению к исходной функции.
  • Следуйте личным соглашениям на основе контекста, например. step и start для аргументов сгиба.
  • Если все остальное не удается, просто перейдите с общим именем, например f

Есть два метода, которых я лично избегаю. Один использует версию апострофа исходной функции, например. hasPair' в предложении where hasPair. Это слишком просто, чтобы случайно написать один, когда вы имели в виду другого; Я предпочитаю использовать go в таких случаях. Но это не огромная сделка, если функции имеют разные типы. Другой использует имена, которые могут означать что-то, но не все, что связано с тем, что на самом деле выполняет функция. napkin попадет в эту категорию. Когда вы пересматриваете этот код, этот выбор названий, вероятно, сбивает вас с толку, так как вы забудете первоначальную причину, по которой вы назвали ее napkin. (Потому что салфетки имеют 4 угла, потому что они легко складываются, потому что они очищают беспорядок? Они найдены в ресторанах?) Другие нарушители - это такие вещи, как bob и myCoolFunc.

Если вы дали функции имя более описательное, чем go или h, то вы должны иметь возможность посмотреть либо контекст, в котором он используется, либо тело функции, и в в обеих ситуациях довольно хорошая идея, почему это имя было выбрано. Вот где мой пункт № 3 приходит: личные соглашения. Применяется большая часть рекомендаций Дона. Если вы используете Haskell в совместной ситуации, тогда координируйте свою команду и определите определенные соглашения для обычных ситуаций.