Любой язык программирования с "странным" вызовом функции? - PullRequest
9 голосов
/ 22 июля 2010

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

function_name(parameter1)function_name_continued(parameter2);

или

function_name(param1)function_continued(param2)...function_continued(paramN);

Например, вы можете вызвать этот вызов функции:

int dist = distanceFrom(cityA)to(cityB);

если вы определили distanceFromto функцию, подобную этой:

int distanceFrom(city A)to(city B)
{
   // find distance between city A and city B
   // ...
   return distance;
}

Насколько я знаю, в языках программирования C, Java и SML это сделать невозможно.

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

Ответы [ 16 ]

6 голосов
/ 22 июля 2010

Очень похоже на синтаксис Smalltalk (который объяснит синтаксис Objective-C - см. Ответ Куби).

Пример:

dist := metric distanceFrom: cityA to: cityB

где #distanceFrom: to: является методомдля некоторого объекта, называемого метрикой.

Таким образом, у вас есть «вызовы функций» (они действительно отправляют сообщения), например

'hello world' indexOf: $o startingAt: 6. "$o means 'the character literal o"

РЕДАКТИРОВАТЬ: я бы сказал «Действительно, #distanceFrom:: должен называться #distanceTo: для класса City, но в любом случае. " Справедливость указывает, что это соединяет город с метрикой, которая является плохой.Существуют веские причины, по которым вы можете захотеть изменить метрику - самолеты могут использовать геодезическую, в то время как автомобили могут использовать кратчайший путь в зависимости от дорожной сети.)

6 голосов
/ 22 июля 2010

Это очень похоже на Objective-C

- (int)distanceFrom:(City *)cityA to:(City *)cityB {
    // woah!
}
4 голосов
/ 22 июля 2010

Для любопытных, Agda2 имеет похожий, очень разрешающий синтаксис. Действительный код:

data City : Set where
  London : City
  Paris  : City

data Distance : Set where
  _km : ℕ → Distance

from_to_ : City → City → Distance
from London to London = 0 km
from London to Paris  = 342 km
from Paris  to London = 342 km
from Paris  to Paris  = 0 km

Если

from Paris to London

оценивается, результат

342 km
3 голосов
/ 22 июля 2010

Очень похоже на свободный интерфейс или метод цепочки для меня.

2 голосов
/ 22 июля 2010

C # 4.0's Именованные и дополнительные аргументы функция позволяет вам достичь чего-то очень похожего:

public static int Distance(string from, string to, string via = "")
{
   ...
}

public static void Main()
{
   int distance;

   distance = Distance(from: "New York", to: "Tokyo");
   distance = Distance(to: "Tokyo", from: "New York");
   distance = Distance(from: "New York", via: "Athens", to: "Tokyo");
}
2 голосов
/ 22 июля 2010

(см. Мое самое любимое личное усилие - окончательный подход C ++ в конце этого ответа)

Language One

Objective-C, но синтаксис вызова[объект сообщения] будет выглядеть так:

int dist = [cities distanceFrom:cityA  to:cityB];

, если вы определили distanceFromto функцию, подобную этой, в объекте города:

- (int)distanceFrom:(City *)cityA to:(City *)cityB 
  {
     // find distance between city A and city B
     // ...
     return distance;
  }

Language Two

Я также подозреваю, что вы могли бы достичь чего-то очень близкого к этому в IO Language , но я только смотрю на это.Вы также можете прочитать об этом по сравнению с другими языками в Семи языках за семь недель , в которых есть бесплатный отрывок о IO.

Language Three

В C ++ существует идиома («цепочка»), в которой вы возвращаете временные объекты или текущий объект, который используется для замены аргументов ключевых слов, согласно Проектирование и развитие C ++ и выглядит так:

int dist = distanceFrom(cityA).to(cityB);

, если вы определили distanceFrom функцию, подобную этой, с небольшим вспомогательным объектом.Обратите внимание, что встроенные функции делают такие вещи компилируемыми в очень эффективный код.

class DistanceCalculator
{
public:
    DistanceCalculator(City* from) : fromCity(from) {}

    int to(City * toCity) 
    {
         // find distance between fromCity and toCity
         // ...
         return distance;
    }

private:
    City* fromCity;
};


inline DistanceCalculator distanceFrom(City* from)
{
    return DistanceCalculator(from);
}

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

class distanceFrom
{
public:
    distanceFrom(City* from) : fromCity(from) {}

    int to(City * toCity) 
    {
         // find distance between fromCity and toCity
         // ...
         return distance;
    }

private:
    City* fromCity;
};

МОЙ ЛЮБИМЫЙ и вот еще более вдохновляющая версия C ++, которая позволяет писать на

int dist = distanceFrom cityA to cityB;

или даже

int dist = distanceFrom cityA to cityB to cityC;

на чудесной комбинации C ++ для #define и классов:

#include <vector>
#include <numeric>
class City;
#define distanceFrom DistanceCalculator() <<
#define to <<

class DistanceCalculator
{
public:

    operator int() 
    {
         // find distance between chain of cities
         return std::accumulate(cities.begin(), cities.end(), 0);
    }

    DistanceCalculator& operator<<(City* aCity)
    {
        cities.push_back(aCity);
        return *this;
    }

private:
    std::vector<City*> cities;
};

NOTE это может выглядеть бесполезным упражнением, но в некоторых контекстах может быть очень полезно дать людям предметно-ориентированный язык в C ++, который они компилируют вместе с библиотеками.Мы использовали аналогичный подход с Python для ученых геомоделирования в CSIRO.

2 голосов
/ 22 июля 2010

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

>>> l = [3,5,1,2,4]
>>> print l.sort.__doc__
L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
cmp(x, y) -> -1, 0, 1
>>> l.sort (reverse=True)
>>> l
[5, 4, 3, 2, 1]

Это очень похоже на то, что делает синтаксис Objective C, помечая каждый аргумент функцией с ее именем.

1 голос
/ 02 августа 2010

Вы можете сделать это в C, хотя и небезопасно:

struct Arg_s
    {
    int from;
    int to;
    };

int distance_f(struct Arg_s args)
    {
    return args.to - args.from;
    }

#define distance(...) distance_f( ((struct Arg_s){__VA_ARGS__}) )
#define from_ .from =
#define to_ .to =

использует составные литералы и обозначенные инициализаторы .

printf("5 to 7 = %i\n",distance(from_ 5, to_ 7));
// 5 to 7 = 2
0 голосов
/ 10 апреля 2018

3 из 4 конфедеративных языков из RemObjects в их компиляторе элементов имеют эту возможность именно в запрошенном синтаксисе OP (для поддержки времени выполнения Objective C, но доступны для всех операционных систем).

в Hydrogene (расширенный C #) https://docs.elementscompiler.com/Hydrogene/LanguageExtensions/MultiPartMethodNames

в Iodine (расширенная Java) https://docs.elementscompiler.com/Iodine/LanguageExtensions/MultiPartMethodNames

в Oxygene (расширенный ObjectPascal), прокрутите вниз до раздела «Имена методов из нескольких частей» https://docs.elementscompiler.com/Oxygene/Members/Methods

0 голосов
/ 26 декабря 2011

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

Это немного тяжелее по сравнению с тем, что вы могли бы пожелать (добро пожаловать, чтобы помочь сделать это проще!) Я думаю, что этоделает то, что вы хотите, и многое другое!

Я приведу реальный пример, потому что целое языка Феликса фактически определяется этим методом (ниже x - нетерминал дляВ выражениях p в x [p] является кодом приоритета):

// alternate conditional
x[sdollar_apply_pri] := x[stuple_pri] "unless" x[let_pri] 
  "then" x[sdollar_apply_pri] =>#
  "`(ast_cond ,_sr ((ast_apply ,_sr (lnot ,_3)) ,_1 ,_5))";

Вот еще немного:

// indexes and slices
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi   'subscript) (,_1 ,_4)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "to" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi 'substring) (,_1 ,_4 ,_6)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" sexpr "to" "]" =># 
  "`(ast_apply ,_sr (,(noi 'copyfrom) (,_1 ,_4)))";
x[sfactor_pri] := x[sfactor_pri] "." "[" "to" sexpr "]" =># 
  "`(ast_apply ,_sr (,(noi 'copyto) (,_1 ,_5)))";

Грамматика Феликса обычный код пользователя .В примерах грамматические действия написаны на схеме.Грамматика это GLR.Он допускает «контекстно-зависимые ключевые слова», то есть идентификаторы, которые являются ключевыми словами только в определенных контекстах, что позволяет легко изобретать новые конструкции, не беспокоясь о нарушении существующего кода.

Возможно, вы хотели бы изучить Грамматика Феликса Онлайн .

...