Каково ваше соглашение об именовании вспомогательных функций?
-
03-07-2019 - |
Вопрос
В функциональном программировании часто важно оптимизировать любой "циклический" код, чтобы он был хвостовым рекурсивным.Однако хвостовые рекурсивные алгоритмы обычно разделяются между двумя функциями - одной, которая настраивает базовый вариант, и другой, которая реализует фактический цикл.Хорошим (хотя и академическим) примером была бы обратная функция.
reverse :: [a] -> [a]
reverse = reverse_helper []
reverse_helper :: [a] -> [a] -> [a]
reverse_helper result [] = result
reverse_helper result (x:xs) = reverse_helper (x:result) xs
"reverse_helper" на самом деле не очень хорошее описательное название.Однако "reverse_recursive_part" - это просто неудобно.
Какое соглашение об именовании вы бы использовали для вспомогательных функций, подобных этой?
Решение
Я обычно добавляю "_recurse" в конец.Итак, "reverse_recurse".Не уверен, откуда я это взял.Мне нравится оставлять базовую функцию простой, как у вас в вашем примере.Как правило, это "общедоступная" функция, и тот факт, что она использует вспомогательную функцию для выполнения итерации, не имеет отношения к вызывающей стороне.В javascript я иногда захожу так далеко, что скрываю итеративную функцию с помощью замыкания, чтобы было действительно ясно, что ее нельзя вызывать напрямую.
Другие советы
Вы можете вызывать вспомогательную функцию как угодно, и это не будет иметь значения до тех пор, пока вы не поместите вспомогательную функцию в "глобальное" пространство имен.Простое добавление "простого числа" кажется обычной практикой.:) Например, в Haskell,
reverse :: [a] -> [a]
reverse = reverse' []
where reverse' :: [a] -> [a] -> [a]
reverse' result [] = result
reverse' result (x:xs) = reverse' (x:result) xs
Я всегда использую do_, например "do_compute" с "compute".Я нахожу это довольно описательным, поскольку фактически это часть функции, которая выполняет действие, в то время как вызываемое "вычисление" должно иметь простое описательное имя для внешнего мира.
Я согласен с ShreevatsaR, если вы не сделаете вспомогательную функцию верхнего уровня (или, что еще хуже, не поместите ее в список экспорта), то не имеет значения, как она называется.Я обычно вызываю вспомогательные функции f
и g
.
reverse :: [a] -> [a]
reverse = f []
where
f ys [] = xs
f ys (x:xs) = f (x:ys) xs
Я просто использую эту схему именования для небольших функций (в противном случае я не знаю, что f
относится к).С другой стороны, зачем вам вообще писать большие функции?
Однако, если вы действительно хотите экспортировать свою вспомогательную функцию, потому что она может быть полезна другим, я бы назвал ее:
reverseAccumulator
Как у Хаскелла zip
и zipWith
.Но я бы не стал называть эти функции "вспомогательными", zipWith
это просто общая функция и zip
это реализация по умолчанию (вероятно, та, которая используется чаще всего).
Я также согласен с ShreevatsaR, в этом примере я бы сделал помощника частной функцией.
В других случаях, когда мне нужно, чтобы вспомогательные функции были видны во всем модуле, но не экспортировались, я обычно ставлю перед функциями префикс '_'.Конечно, есть явное указание exports, но во время разработки я обычно экспортирую все функции, чтобы упростить интерактивное изучение, напримерв ghci.Позже я добавляю список экспортированных функций, и нижняя панель позволяет легко запомнить, предполагал ли я, что функция будет локальной или нет.
Я использую aux
или foo_aux
(для основной функции foo
), и вложите определение так, чтобы оно не было видно извне.
настройка и выполнение
пример:
function whateverSetup() { ... }
function whateverExecute() { ... }