Какво прави едно добро име за помощна функция?

Помислете за следния проблем: даден списък с дължина три от кортежи (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" изглежда като добър избор, но вече е зает! Намирам, че този модел се появява често - естествено изглеждащото име за помощна функция вече е взето от външната функция, която я извиква. Така че понякога съм наричал такива помощни функции неща като "оп", "фу" и дори "помощник" - тук избрах "салфетка", за да подчертая нейната употреба веднъж, изхвърляне.

И така, скъпи читатели на Stackoverflow, какво бихте нарекли „салфетка“? И което е по-важно, как подхождате към този въпрос като цяло?


person gcbenison    schedule 24.05.2012    source източник
comment
go е пътят :)   -  person Riccardo T.    schedule 24.05.2012
comment
Обща метрика - използвайте кратки описателни имена, ако се затруднявате да бъдете подходящо описателни, просто ги направете кратки. Между другото napkin, както е написано в момента, не е много стабилно (списъкът трябва да има точно три члена), ако помислите малко повече, може би ще предложи по-добро име.   -  person stephen tetley    schedule 24.05.2012
comment
@stephen Да, разбрах това за napkin, докато го пишех. Бихте ли казали, че това е вярно като цяло: ако ви е трудно да наименувате функция, вашият дизайн вероятно има нужда от подобрение? Ако е вярно, това е доста мощна концепция...   -  person gcbenison    schedule 24.05.2012
comment
@gcbenison - за функции от най-високо ниво, съгласен съм с вашата максима. Заплетените имена са сигнал, че нещо не е достатъчно разработено.   -  person stephen tetley    schedule 25.05.2012
comment
Няма ли нов hasPair, дефиниран в where close, да има предимство и да скрие външния? В такъв кратък код има малък риск от объркване ...   -  person Vincent Beffara    schedule 27.05.2012
comment
@vincent Да, прав си, не бях разбрал, че hasPair ще работи за името на помощната функция. Въпреки това много хора обикновено смятат скриването на външни обвързвания за вредно.   -  person gcbenison    schedule 27.05.2012


Отговори (4)


Общи правила за именуване на променливи с локален обхват.

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

Те обикновено се прилагат само за аргументи към HOF. За вашия случай бих избрал нещо като k или eq3.

Използвайте пестеливо апострофите за производни стойности.

person Don Stewart    schedule 24.05.2012
comment
Само за да бъде ясно за всеки, който чете това: това не са правила на езика Haskell, те са (много общи) конвенции. - person huon; 24.05.2012
comment
Не е ли k конвенционалното име специално за продълженията? - person Heatsink; 24.05.2012
comment
О, да, и p и q за предикати. - person Don Stewart; 24.05.2012
comment
m за параметър, който е монадично действие, напр. f >>= m = …, добре за функции тип when/withSomeResource. p за анализатори. - person Christopher Done; 26.05.2012

Склонен съм да извиквам функции с булеви стойности p за предикат. pred, за съжаление, вече е заето.

person sclv    schedule 24.05.2012

В случаи като този, когато вътрешната функция е основно същата като външната функция, но с различни предварителни условия (изискващи списъкът да е сортиран), понякога използвам същото име с просто число, напр. 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)
person hammar    schedule 25.05.2012
comment
Да, това изглежда отразява тезата на @stephen, че по-добрият дизайн естествено води до по-добри имена. - person gcbenison; 25.05.2012
comment
Дали това използване на hasPair' ще бъде в съответствие с @don Използвайте пестеливо апострофите за производни стойности? - person gcbenison; 25.05.2012
comment
Подкрепям това. Не се страхувайте от няколко допълнителни дефиниции от най-високо ниво, това особено улеснява отстраняването на грешки, тъй като можете да проверите поведението на поддържащите функции отделно от поддържаните. Използвайте изрично експортиране на модули, ако се притеснявате от излагането на конкретен API. - person Dan Burton; 27.05.2012

Стратегията ми следва доста точно предложенията на Дон:

  1. Ако има очевидно име за него, използвайте го.
  2. Използвайте go, ако е "worker" или по друг начин е много подобна на оригиналната функция.
  3. Следвайте личните конвенции въз основа на контекста, напр. step и start за аргументи към сгъване.
  4. Ако всичко друго се провали, просто изберете общо име, като f

Има две техники, които аз лично избягвам. Едната е използването на версията с апостроф на оригиналната функция, напр. hasPair' в клаузата where на hasPair. Твърде лесно е случайно да напишете едното, когато сте имали предвид другото; Предпочитам да използвам go в такива случаи. Но това не е голяма работа, стига функциите да имат различни типове. Другото е използването на имена, които може да означават нещо, но не нещо, което има общо с това, което функцията всъщност прави. napkin ще попадне в тази категория. Когато прегледате отново този код, този избор на име вероятно ще ви озадачи, тъй като ще сте забравили първоначалната причина, поради която сте го кръстили napkin. (Защото салфетките имат 4 ъгъла? Защото се сгъват лесно? Защото почистват бъркотии? Намират се в ресторантите?) Други нарушители са неща като bob и myCoolFunc.

Ако сте дали на функция име, което е по-описателно от go или h, тогава трябва да можете да разгледате или контекста, в който се използва, или тялото на функцията, и в двете ситуации да получите доста добра представа защо е избрано това име. Тук идва моята точка № 3: лични конвенции. Голяма част от съветите на Дон са приложими. Ако използвате Haskell в ситуация на сътрудничество, координирайте се с вашия екип и вземете решение за определени конвенции за често срещани ситуации.

person Dan Burton    schedule 26.05.2012