Я пишу о синтаксисе языка. Есть ли какой-нибудь язык, в котором параметры помещаются внутри имени метода?

29

в JavaScript:

function getTopCustomersOfTheYear(howManyCustomers, whichYear) {
   // Some code here.
}
getTopCustomersOfTheYear(50, 2010);

в C #:

public List<Customer> GetTopCustomersOfTheYear(int howManyCustomers, 
 int whichYear)
{
   // Some code here
}
List<Customer> customers = GetTopCustomersOfTheYear(50, 2010);

в PHP:

public function getTopCustomersOfTheYear($howManyCustomers, $whichYear)
{
   // Some code here
}
$customers = getTopCustomersOfTheYear(50, 2010);

Есть ли какой-нибудь язык, который поддерживает этот синтаксис:

function GetTop(x)CustomersOfTheYear(y)
{
    // Some code here
}
returnValue = GetTop(50)CustomersOfTheYear(2010);

Разве это не более семантическая, более читаемая форма написания функции?

Обновление: причина, по которой я задаю этот вопрос, заключается в том, что я пишу статью о новом синтаксисе для нового языка. Однако я подумал, что наличие такого синтаксиса для объявления методов может быть более приятным и более дружественным для разработчиков и уменьшит кривую изучения языка, поскольку он ближе к естественному языку. Я просто хотел знать, была ли эта функция уже рассмотрена или нет.

Saeed Neamati
источник
12
Возможно, вам будет легче читать, когда вы привыкнете к этой идиоме, но мне кажется, что будет сложно написать правильный парсер для этого.
Мейсон Уилер
2
Что вы подразумеваете под "заполнителями"? Этот вопрос трудно понять как поставленный, хотя последний пример кода напоминает Objective-C и SmallTalk.
Greyfade
3
AFAIK Smalltalk был первым языком, использующим этот синтаксис исключительно как 'hello world' indexOf: $o startingAt: 6или Rectangle width: 100 height: 200. Кстати, что не так с этим вопросом?
Maaartinus
8
Если вы переместите скобку, вы получите: returnValue = GetTop(50, CustomersOfTheYear(2010))что выглядит для меня одинаково читабельным, и на самом деле более гибким / ортогональным. ... и да, это обычный синтаксис.
dagnelies
2
@arnaud: Я полностью согласен. Предложенный синтаксис - только обходной путь для отсутствия декомпозиции.
back2dos

Ответы:

41

Да и да. Да, есть такой язык, и да, многие люди находят его более читабельным, когда привыкнут к нему.

В Objective-C этот метод будет:

- (NSArray*)getTop:(int)count customersOfTheYear:(Year)year;

На самом деле это довольно надуманный пример, который не очень хорошо читается, поэтому вот лучший пример из реального кода:

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

Это прототип для метода, который возвращает новый экземпляр UIColor, используя значения красного, зеленого, синего и альфа. Вы бы назвали это так:

UIColor *violet = [UIColor colorWithRed:0.8 green:0.0 blue:0.7 alpha:1.0];

Узнайте больше об именах сообщений с разбросанными параметрами на языке программирования Objective-C .

Калеб
источник
16
В первый раз, когда я прочитал об этом в Objective CI, я подумал, что это умно, но на самом деле названные параметры стали более жесткими и сложными в управлении. Кроме того, хороший ответ.
ZJR
2
Пример того, как метод вызывается, не будет ошибочным.
серый
3
@ZJR, несмотря на мнение Википедии об обратном , стиль Obj-C похож на именованные параметры, но отличается. В приведенном выше примере, метод название: +colorWithRed:blue:green:alpha:. Я случайно использовать имена параметров , которые соответствуют методу, но я мог бы так же легко использовал r, b, gи a. С именованными параметрами, такими как предложения JavaScript, вы будете использовать фактические имена, данные для доступа к значениям. Параметры истинных имен также могут быть заданы в любом порядке, а параметры могут быть необязательными. Так похоже, да, но принципиально отличается.
Калеб
2
Я думал Python: color(r=0xFF,g=0xFF,b=0x55)или color(b=0x32,r=0x7F,a=.5,g=0xFF)и так далее. Давайте тогда назовем эти очень именованные параметры . :)
ZJR
3
@ZJR, ваш пример с Python прав - это именно то, что я бы назвал «именованными параметрами». Я просто говорю, что Obj-C действительно не дает вам этого вообще. Синтаксис выглядит очень похоже именованных параметров в JavaScript , так как метод разбит на части, и каждая часть имеет двоеточие, но это на самом деле не то, что на всех . Имена в Obj-C являются частью имени метода, а не именами, которые можно использовать для ссылки на параметры в реализации; порядок имеет значение; параметры не являются обязательными. Я подозреваю, что мы, вероятно, согласны больше, чем нет.
Калеб
25

Ответ: smalltalk

http://en.wikipedia.org/wiki/Smalltalk

'hello world' indexOf: $o startingAt: 6 это как Java "hello world".indexOfStartingAt(o, 6)

Rectangle width: 100 height: 200 это как Java new Rectangle(100, 200)

Синтаксис ... expression word1: parm1 word2: parm2 word3: parm3 ...Имя вызываемого метода является объединением всех слов.

Джефф Григг
источник
17

Я считаю, что вы ищете абстракцию под названием " свободный интерфейс (настоящим я поднимаю комментарий, первоначально сделанный @Jesper, к «ответу»). » Этот общий шаблон был успешно реализован во многих языках, из которых Objective-C - только один.

Вот довольно чистый пример:

Person bo = new Person();
bo.Set.FirstName("Bo").LastName("Peep").Age(16).Size("Little").LostHerSheep();

Вы можете увидеть , как что - то , как это может быть реализовано в Randy Patterson «с Как создать свободный интерфейс» .

Андре Вианна дает краткую историю, а затем обсуждает возможные реализации еще в двух частях статьи, включая множество полезной информации. Вианна указывает на старую идею, с которой я впервые столкнулся в Smalltalk 80, - « каскадирование », которая позволяла отправлять несколько сообщений одному и тому же объекту. Это выглядело так:

aThing one: 'one';
  two: 'two';
  other.

Впоследствии каскадирование превратилось в « цепочку методов », где мы « Методы модификаторов Make возвращают хост-объект, так что несколько модификаторов могут быть вызваны в одном выражении ». Позже цепочка методов выросла, чтобы стать свободным интерфейсом. концепцией мы знаем и часто используем сегодня , То, что вы планируете сделать, выглядит очень похоже.

Айенде Рахин обсуждает, как «плавный интерфейс» может существенно отличаться от «цепочки методов», чтобы заслужить свое имя .

Свободные интерфейсы обычно встречаются в некоторых новых инструментах, используемых в поведенчески-ориентированной разработке (BDD), и даже нашли свое применение в NUnit , основном инструменте для модульного тестирования .NET, в своей новой модели Assert на основе ограничений .

Эти основные подходы впоследствии были реализованы на других языках, включая Ruby, Python, C #, Objective-C и Java . Чтобы реализовать нечто подобное, вам нужно изучить идею « замыкания », которая имеет фундаментальное значение для цепочки и беглости.

Возможно, вы можете улучшить эти модели; Вот так мы получаем отличные новые языки. Тем не менее, я верю, что полное понимание цепочки методов и быстрых интерфейсов даст вам отличную отправную точку для развития ваших идей!

Джон Тоблер
источник
2
+1 для наиболее исследованного ответа, хотя добавление примеров и переформулировка для удобочитаемости могут помочь.
Хайлем
@haylem, спасибо, что заставили меня вернуться и добавить примеры и немного больше деталей!
Джон Тоблер
3
Проголосовал, потому что это хорошее описание свободного стиля, но, пожалуйста, обратите внимание, что это действительно не то, о чем спрашивает OP. Когда я это читаю, вопрос касается распределения параметров между частями имени одной функции или метода . Обратите внимание на предлагаемую декларацию функции: function GetTop(x)CustomersOfTheYear(y). Это отдельная функция, а не цепочка вызовов двух разных функций.
Калеб
@Caleb Я думаю, что здесь он пытается указать, что эти инфиксные параметры являются негибким способом создания свободного интерфейса (этот ответ) или именованных параметров (другой ответ). До сих пор я не видел для них никакого преимущества в том, что свободный интерфейс / именованные параметры не могут работать лучше.
Иската,
16

Objective-C делает это. Вот типичный прототип:

- (void) areaWithHeight: (float) height andWidth: (float) width;

Вот как вы называете такой метод:

float area = [self areaWithHeight: 75 andWidth: 20];

Objective-C в основном используется с Cocoa для Mac OS X и Cocoa Touch для iOS, но gcc будет создавать код Objective-C практически на каждой платформе, на которой работает gcc.

Майк Кроуфорд
источник
Извините, что пуля должна была быть дефисом. Я думаю, дефисы в тексте ответа принимаются за разметку. Дефисы в Objective-C используются для объявления методов, которые принадлежат объекту - [foo bar: x], где foo - это экземпляр объекта или класса - в то время как знаки плюс используются для методов класса, что в C ++ называется статическими функциями-членами.
Майк Кроуфорд
13

В Common lisp вы можете определить ключевые аргументы для такой функции:

(defun area (&key width height)
    (* width height))

Функция вызывается так:

(area :width 2 :height 3)

В Ada вам не нужно специальное объявление - вы можете вызвать любую процедуру или функцию поочередно, перечислив аргументы по порядку или назвав аргументы следующим образом:

a := area(width => 2, height => 3);

Наконец, библиотека Boost включает слой хаков для добавления этой функции в C ++: http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html.

хан
источник
5

Я не смог найти его название, но есть шаблон проектирования для выполнения чего-то похожего, где вызов функции возвращает новый объект, измененный, как описано. Например:

query = db.getTopCustomers(50).forYear(2010);

Он используется не очень часто, потому что ваши данные должны быть очень ортогональными, чтобы избежать неуправляемой сложности под капотом, но могут быть полезны в правильных обстоятельствах.

Карл Билефельдт
источник
6
Это называется свободным стилем дизайна интерфейса .
Джеспер
@Jesper, то, что я вижу, очень похоже на цепочку jQuery. Я прав?
Саид Нимати
Да, @Saeed, jQuery использует этот стиль.
Карл Билефельдт
5

Python имеет ключевые параметры. Пример определения функции

def getTopCustomers(count,year):
...

Пример вызова функции

x = getTopCustomers(year=1990, count=50)

(Я понимаю, что это не совсем в духе первоначального вопроса, но если параметры ключевого слова в lisp соответствуют требованиям, то сделайте это. Однако в Smalltalk и Objective-C ключевые слова между аргументами действительно являются частью имени функции / поиска .)

Дэвид Андерссон
источник
Мне лично это нравится больше, потому что это дает вам возможность вызывать функцию без имен параметров, если вы знаете порядок параметров
Пабло Мешер
4

Агда имеет миксфиксную запись

if_then_else x y z = case x of
                     True -> y
                     False -> z

 if cond then x else y

Всякий раз, когда функция названа с подчеркиванием, она может быть разделена на две части с аргументом между

Даниэль Гратцер
источник
4

Пока не язык программирования как таковой , Cucumber принимает параметры в середине имен функций, которые могут содержать пробелы и должны выглядеть как английский.

Однако «функции» определены в Ruby

# definition
Given /^I calculate (.*) times (.*)$/ do |x, y|
    @result = x.to_i * y.to_i
end

Then /^the result should be (.*)$/ do |v|
    @result.should == v.to_i
end

# usage
Scenario:
    Given I calculate 6 times 9
    Then the result should be 42
конфигуратор
источник
4

В TeX вы можете определять макросы, имеющие «шаблон аргумента», который в основном означает, что ваш протокол вызова бесплатный. Для вашего конкретного примера вы можете использовать

\def\getTopCustomers#1OfTheYear#2;{%
  The #1 top customers of the year #2.
}
\getTopCustomers 50 OfTheYear 2010;

Обратите внимание, что также можно избавиться от ; если вы согласны играть с регистрами:

\newcount\customers
\newcount\year
\def\getTopCustomers#1OfTheYear{%
  \customers#1\relax
  \afterassignment\reallyGetTopCustomersOfTheYear
  \year
}
\def\reallyGetTopCustomersOfTheYear{%
  The {\the\customers} top customers of the year {\the\year}.
}
\getTopCustomers 50 OfTheYear 2010

TeX позволяет вам перенастроить свой лексер, и благодаря \afterassignment макросу, который я использовал выше, вы можете использовать встроенные процедуры для лексирования чисел. Это очень полезно для определения очень кратких протоколов вызова. Например, очень вероятно написать макрос TeX, понимающий нотацию Markdown для таблиц.

Теперь вы спрашиваете: «Как мне получить доступ к моей базе данных, где хранятся клиенты из TeX?», Но это другой вопрос. :)

В Common lisp определенно можно определить queryмакрос, позволяющий писать

(query getTopCustomers 50 OfTheYear 2010)

где getCustomers и OfTheYear интерпретируются как символы. Тогда работа макроса заключается в том, чтобы разобраться в этом. Common lisp превосходен в области читабельности кода (да, я имею в виду!), Потому что система макросов позволяет легко создавать псевдоязыки, настроенные для вашего приложения. (Я думаю, что они называются языками приложений.)

PS: похоже, никто не цитировал C ++. Самое близкое, что вы можете получить (без препроцессора)

query.getTopCustomers(50).OfTheYear(2010):

хитрость заключается в том, чтобы getTopCustomersвозвращает ссылку на query(или что - нибудь еще) , что также орудия OfTheYear. Вы можете построить этот пример до небольшого языка запросов, но затем вам нужно определить конечные свойства (возвращая значение) или добавить finaliseметод (выполнить поиск и вернуть значение). Если вам это нравится, вы также можете имитировать потоковые контроллеры STL и иметь возможность писать такие вещи, как

query << getTopCustomers(50) << OfTheYear(2010) << flush;

но это снова идет в направлении языков приложений.

Редактировать: я пропустил @han ответы, которые также цитируют Common Lisp и C ++ (но не TeX!).

Michael Grünewald
источник
2

В JavaScript или любом другом языке , который поддерживает закрытие, вы можете снискать такую функцию:

function getTopCustomersFunc(count) {
    return function(year) {
       // run some query, return count customers from year
    }
}
var top20Func = getTopCustomersFunc(20);
var top20Customers2005 = top20Func(2005);
var top20Customers2008 = top20Func(2008);
Jiggy
источник
1
+1, потому что это интересно, но помните, что '20' в top20Func больше не является параметром, а частью имени, которое напоминает вам о параметре. Вы можете так же легко сказать: var top5Func = getTopCustomersFunc(37);. «5» вводит в заблуждение, но код работает точно так же, как если бы переменная была названа top37Func.
Калеб
1

Это зависит от вашего определения «языка», но среда тестирования роботизированной конструкции позволяет вам определять ключевые слова таким образом. Из их документации по встроенным аргументам :

Select ${animal} from list | Open page | pet selection
                            | Select item from list | animal_list | ${amimal}

Выше объявляется новое ключевое слово (по существу, функция) с именем «select $ {animal} from list», где «$ {animal}» является параметром. Вы называете это как «выбрать кота из списка»

Брайан Оукли
источник
Это кажется мне как операторы SQL. +1
Саид Нимати
1

Сообщите 7.

To create (employee - a person) being paid (salary - a number):
    say "Welcome to your new job, [name of employee]!";
    choose a blank row from the table of employees;
    now the paid entry is the salary;
    now the name entry is the name of the employee.

И так далее.

Рон Ньюкомб
источник
3
Это не совсем объясняет, как работает синтаксис языка. Многие люди не знакомы с языком Inform и не могут отличить параметры от вызова или его использования в других областях кода.
Я отчасти заинтригован этим языком. Ответ был довольно коротким, только с не разработанным образцом кода, но также и с примерами, предоставленными ФП (хотя и с более традиционными языками). В Вики есть хорошая статья, чтобы прочитать об этом.
YoYo
0

Ключевые слова Common Lisp уже упоминались, но макросы Common Lisp также позволяют это довольно легко:

(defmacro get-my-element (from list at index)
  `(nth ,index ,list))

Это можно затем назвать так:

(get-my-element from '(a b c) at 1) ;returns B

Однако следует отметить, что условия from и atне соблюдаются. Там должно быть что- то, пропустить их полностью - ошибка, но поскольку макрос просто отбрасывает их, не имеет большого значения, что они за пределами читабельности (что важно):

(get-my-element from '(a b c) 3 1) ;also returns B
8bittree
источник
-2

В Clojure обычно используются ключевые аргументы для таких ситуаций, как, например:

(get-customers :top 50 :year 2010)

Аргументы ключевых слов достаточно гибкие, они могут быть необязательными и иметь значения по умолчанию и т. Д.

mikera
источник
-4

Вы можете подражать этому в Python. Например,

def GetTop(customers, ofYear):
  #write some code here to get the customers

print GetTop(customers=50 ofYear=2010)

или даже

def GetTop(**args):
  #write some code here using the same parameter names as above

print GetTop({customers: 50, ofYear: 2010})
кодер108
источник
1
Синтаксис в вашем втором примере неверен. Кроме того, кто-то уже опубликовал это.
Уинстон Эверт
это просто повторяет высказанную точку зрения (и гораздо лучше объясненную) в этом предыдущем ответе , опубликованном 3 годами ранее
комнат