任何具有“奇怪”特征的编程语言函数调用?

发布于 2024-09-10 14:47:18 字数 593 浏览 1 评论 0 原文

我想知道,是否有任何编程语言可以进行这样的函数调用:

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编程语言中,这是无法做到的。

您是否知道任何可以让您定义和调用的编程语言 这样的功能?

I was wondering, is there any programming language where you can have function calls like this:

function_name(parameter1)function_name_continued(parameter2);

or

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

For example you could have this function call:

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

if you have defined distanceFromto function like this:

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

As far as I know, in C, Java and SML programming languages, this cannot be done.

Are you aware of any programming language that let's you define and call
functions in this way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

听不够的曲调 2024-09-17 14:47:18

它看起来非常像 Objective-C

- (int)distanceFrom:(City *)cityA to:(City *)cityB {
    // woah!
}

It looks an awful lot like Objective-C

- (int)distanceFrom:(City *)cityA to:(City *)cityB {
    // woah!
}
铁轨上的流浪者 2024-09-17 14:47:18

听起来很像 Smalltalk 的语法(这可以解释 Objective-C 的语法 - 请参阅 kubi 的答案)。

示例:

dist := metric distanceFrom: cityA to: cityB

其中 #distanceFrom:to: 是某个名为 metric 的对象上的方法。

所以你有“函数调用”(它们实际上是消息发送),比如

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

编辑:我说过“真的,#distanceFrom:to: 应该在 City 类上调用 #distanceTo:,但无论如何。” Justice 指出,这将城市与指标联系在一起,这是不好的。您可能想要改变度量标准的原因有很多——飞机可能使用测地线,而汽车可能使用基于道路网络的最短路径。)

Sounds a lot like Smalltalk's syntax, (which would explain Objective-C's syntax - see kubi's answer).

Example:

dist := metric distanceFrom: cityA to: cityB

where #distanceFrom:to: is a method on some object called metric.

So you have "function calls" (they're really message sends) like

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

EDIT: I'd said "Really, #distanceFrom:to: should be called #distanceTo: on a City class, but anyway." Justice points out that this couples a City to a Metric, which is Bad. There are good reasons why you might want to vary the metric - aeroplanes might use a geodesic while cars might use a shortest path based on the road network.)

请你别敷衍 2024-09-17 14:47:18

出于好奇,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

For the curious, Agda2 has a similar, very permissive syntax. The following is valid code:

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

If

from Paris to London

is evaluated, the result is

342 km
嘿嘿嘿 2024-09-17 14:47:18

看起来很像流畅的界面方法链接给我。

Looks a lot like a fluent interface or method chaining to me.

黯然 2024-09-17 14:47:18

在 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 语法所做的事情,标记每个参数到一个带有其名称的函数。

In Python, you can explicitly pass the name of the arguments you're calling the function with, which lets you pass them in a different order or skip optional arguments:

>>> 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]

This looks a lot like what the Objective C syntax is doing, tagging each argument to a function with its name.

那支青花 2024-09-17 14:47:18

C# 4.0 的 命名和可选参数 功能允许您实现非常相似的目标:

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");
}

C# 4.0's Named and Optional Arguments feature allows you to achieve something pretty similar:

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");
}
你对谁都笑 2024-09-17 14:47:18

(请参阅我最喜欢的个人努力 - 本答案末尾的最终 C++ 方法)

语言一

Objective-C 但调用语法是 [object message] 所以看起来像:

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

如果您定义了 < code>distanceFromto 像这样的函数,城市对象中:

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

语言二

我也怀疑你可以在 IO Language 但我只是看看它。您可能还想了解它与其他语言的比较 七周掌握七种语言,其中有关于 IO 的免费摘录

第三种语言

根据 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;

基于#define 和类的精彩 C++ 风格组合:

#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;
};

注意这可能看起来像是一个无用的练习,但在某些情况下它可以是对于为人们提供 C++ 中的特定于领域的语言非常有用,他们可以将其与库一起编译。我们对 CSIRO 的地理建模科学家使用了类似的 Python 方法。

(see my very favourite personal effort - the final C++ approach at the end of this answer)

Language One

Objective-C but the calling syntax is [object message] so would look like:

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

if you have defined distanceFromto function like this, within a cities object:

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

Language Two

I also suspect you could achieve something very close to this in the IO Language but I'm only just looking at it. You may also want to read about it in comparison to other languages in Seven Languages in Seven Weeks which has a free excerpt about IO.

Language Three

There's an idiom ("chaining") in C++ where you return temporary objects or the current object that is used to replace keyword arguments, according to The Design and Evolution of C++ and looks like this:

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

if you have defined distanceFrom function like this, with a little helper object. Note that inline functions make this kind of thing compile to very efficient code.

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);
}

Duhh, I was in a hurry earlier, realised I can refactor to just use a temporary object to give the same syntax:

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

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

private:
    City* fromCity;
};

MY FAVOURITE
and here's an even more inspired C++ version that allows you to write

int dist = distanceFrom cityA to cityB;

or even

int dist = distanceFrom cityA to cityB to cityC;

based on a wonderfully C++ ish combination of #define and classes:

#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 this may look like a useless exercise but in some contexts it can be very useful to give people a domain-specific language in C++ which they compile alongside libraries. We used a similar approach with Python for geo-modeling scientists at the CSIRO.

往事随风而去 2024-09-17 14:47:18

您可以在 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 =

使用 compound文字指定初始化器

printf("5 to 7 = %i\n",distance(from_ 5, to_ 7));
// 5 to 7 = 2

You can do this in C, albeit unsafely:

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 =

uses compound literals and designated initializers.

printf("5 to 7 = %i\n",distance(from_ 5, to_ 7));
// 5 to 7 = 2
濫情▎り 2024-09-17 14:47:18

RemObjects 的 Elements Compiler 中的 4 种联合语言中的 3 种在 OP 所请求的语法中具有此功能(以支持 Objective-C 运行时,但可用于所有操作系统)。

在 Hydrogene(扩展的 C#)中

(扩展的 Java)
https://docs.elementscompiler.com/Iodine/LanguageExtensions/MultiPartMethodNames

Oxygene 中的 (扩展的 ObjectPascal),向下滚动到多部分方法名称部分
https://docs.elementscompiler.com/Oxygene/Members/Methods

3 of the 4 confederated languages from RemObjects in their Elements Compiler have this capability in precisely the OP's requested syntax (to support Objective-C runtime, but made available to all operating systems).

in Hydrogene (an extended C#)
https://docs.elementscompiler.com/Hydrogene/LanguageExtensions/MultiPartMethodNames

in Iodine (an extended Java)
https://docs.elementscompiler.com/Iodine/LanguageExtensions/MultiPartMethodNames

in Oxygene (an extended ObjectPascal), scroll down to Multi-Part Method Names section
https://docs.elementscompiler.com/Oxygene/Members/Methods

活雷疯 2024-09-17 14:47:18

这看起来类似于函数重载 (C++/C#)/默认参数 (VB)。

默认参数允许定义函数的人为后面的参数设置默认值:

例如c#重载:

int CalculateDistance(city A, city B, city via1, city via2) 
{....}

int CalculateDistance(city A, city B) 
{
  return CalculateDistance(city A, city B, null, null)
}

This looks similar to function overloading (C++/C#)/default parameters (VB).

Default Parameters allow the person defining the function to set defaults for the latter parameters:

e.g. c# overloading:

int CalculateDistance(city A, city B, city via1, city via2) 
{....}

int CalculateDistance(city A, city B) 
{
  return CalculateDistance(city A, city B, null, null)
}
对不⑦ 2024-09-17 14:47:18

您可以为此使用成员函数。

cityA.distance_to(cityB);

这是 C++、C(稍作调整)、C#、Java 中的有效代码。使用方法链,您可以执行以下操作:

cityA.something(cityB).something(cityC).something(cityD).something(cityE);

You can use a member function for this.

cityA.distance_to(cityB);

That's valid code in C++, C(with a little tweaking), C#, Java. Using method chains, you can do:

cityA.something(cityB).something(cityC).something(cityD).something(cityE);
最好是你 2024-09-17 14:47:18

在 SML 中,您可以简单地将“to”设置为某个值(例如单位),并将“distanceFrom”设置为带有三个参数的柯里化函数。例如:

val to = ()
fun distanceFrom x _ y = (* implementation function body *)

val foo = distanceFrom cityA to cityB

您还可以利用 SML 不强制执行 datataype 构造函数命名约定的事实(这让很多人感到烦恼),因此如果您想确保类型系统强制执行您的自定义语法:

datatype comp = to

fun distanceFrom x to y = (* implementation *)

val foo = distanceFrom cityA to cityB (* works *)
val foo' = distanceFrom cityA cityB (* whoops, forgot 'to' - type error! *)

In SML you could simply make "to" some value (unit, for example), and "distanceFrom" a curried function that takes three parameters. For example:

val to = ()
fun distanceFrom x _ y = (* implementation function body *)

val foo = distanceFrom cityA to cityB

You could also take advantage of the fact that SML doesn't enforce naming conventions on datataype constructors (much to many peoples' annoyance), so if you want to make sure that the type system enforces your custom syntax:

datatype comp = to

fun distanceFrom x to y = (* implementation *)

val foo = distanceFrom cityA to cityB (* works *)
val foo' = distanceFrom cityA cityB (* whoops, forgot 'to' - type error! *)
生生不灭 2024-09-17 14:47:18

您可以在Scheme 或LISP 中使用宏来完成此操作。

形式类似于:

(DISTANCE-FROM city-a TO city-b)

大写的符号表示语法。

您甚至可以执行“命名参数”之类的操作:

(DISTANCE TO city-a FROM city-b)
(DISTANCE FROM city-a TO city-b)

You could do this in Scheme or LISP using macros.

The form will be something like:

(DISTANCE-FROM city-a TO city-b)

The symbols in uppercase denotes syntax.

You could even do something like 'named parameters':

(DISTANCE TO city-a FROM city-b)
(DISTANCE FROM city-a TO city-b)
余生一个溪 2024-09-17 14:47:18

Tcl 允许你做这样的事情:

proc distance {from cityA to cityB} {...}
set distance [distance from "Chicago IL" to "Tulsa OK"]

我不确定这是否正是你所想的。

Tcl allows you to do something like this:

proc distance {from cityA to cityB} {...}
set distance [distance from "Chicago IL" to "Tulsa OK"]

I'm not sure if that's quite what you are thinking of though.

此刻的回忆 2024-09-17 14:47:18

您可以在Java中执行此操作,使用构建器模式 出现在 Joshua Bosch 的《Effective Java》一书中(这是我第二次将此链接放在 SO 中,我仍然没有使用那种模式,但看起来很棒)

You can do it in Java, Use Builder pattern that appears in the book Effective Java by Joshua Bosch (this is second time I put this link in SO, I still didn't use that patern, but looks great)

时常饿 2024-09-17 14:47:18

那么,在 Felix 中,您可以分两步实现:首先,编写一个普通函数。然后,您可以扩展语法并将一些新的非终结符映射到函数。

与您可能想要的相比,这有点重量级(欢迎帮助使其变得更容易!!)我认为这可以满足您的需求,甚至更多!

我将举一个真实的例子,因为整个 Felix 语言实际上都是通过这种技术定义的(下面的 x 是表达式的非终结符,x[p] 中的 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)))";

Felix 语法是普通用户代码。在示例中,语法操作是用Scheme 编写的。语法是GLR。它允许“上下文敏感关键字”,即标识符仅在某些上下文中是关键字,这使得发明新结构变得容易,而不必担心破坏现有代码。

也许您想查看Felix Grammar Online

Well, in Felix you can implement this in two steps: first, you write an ordinary function. Then, you can extend the grammar and map some of the new non-terminals to the function.

This is a bit heavyweight compared to what you might want (welcome to help make it easier!!) I think this does what you want and a whole lot more!

I will give a real example because the whole of the Felix language is actually defined by this technique (below x is the non-terminal for expressions, the p in x[p] is a precedence code):

// 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))";

Here's a bit more:

// 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)))";

The Felix grammar is ordinary user code. In the examples the grammar actions are written in Scheme. The grammar is GLR. It allows "context sensitive keywords", that is, identifiers that are keywords in certain contexts only, which makes it easy to invent new constructs without worrying about breaking existing code.

Perhaps you would like to examine Felix Grammar Online.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文