我正在写有关语言语法的文章。在方法名称中是否存在将参数置于其中的语言?


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

编写函数不是更语义,更易读的形式吗?

更新:我问这个问题的原因是,我正在写一篇有关一种新语言的新语法的文章。但是,我认为拥有这样的语法来声明方法可能对开发人员来说更好,更友好,并且会降低语言的学习曲线,因为它更接近自然语言。我只是想知道是否已经考虑过此功能。


12
一旦习惯了这种习惯用法,阅读起来可能会更容易,但是在我看来,为此编写一个正确的解析器将很困难。
梅森惠勒

2
您所说的“占位符”是什么意思?尽管最后一个代码示例让人联想到Objective-C和SmallTalk,但这个问题很难理解。
greyfade11年

3
AFAIK Smalltalk是使用此语法的唯一语言,如'hello world' indexOf: $o startingAt: 6Rectangle width: 100 height: 200。顺便说一句,这个问题怎么了?
maaartinus

8
如果您移动括号,则会得到:returnValue = GetTop(50, CustomersOfTheYear(2010))在我看来,它具有同等可读性,实际上更灵活/正交。...是的,这是普通的普通语法。
dagnelies,2011年

2
@arnaud:我完全同意。提出的语法只是缺乏分解的一种解决方法。
back2dos

Answers:


41

是的,是的。是的,有这样一种语言,是的,许多人一旦习惯了它,就会发现它更具可读性。

在Objective-C中,方法为:

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

实际上,这是一个非常人为的示例,阅读起来并不很好,因此,这是来自实际代码的一个更好的示例:

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

该方法的原型使用红色,绿色,蓝色和alpha值返回新的UIColor实例。您可以这样称呼它:

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

《 Objective-C编程语言》中阅读有关带有散布参数的消息名称的更多信息。


16
第一次在Objective CI中阅读它时认为它很聪明,但是实际上它的命名参数变得更加僵硬且难以管理。除此之外,好的答案。
ZJR

2
如何调用该方法的示例不会出错。
greyfade

3
@ZJR,尽管Wikipedia意见相反,但是Obj-C的样式就像命名参数一样,但是有所不同。在上面的示例中,方法名称为:+colorWithRed:blue:green:alpha:。我碰巧使用的名称相匹配的方法测得的参数,但我可以容易地使用rbg,和a。使用诸如JavaScript产品之类的命名参数,您将使用给定的实际名称来访问值。真实名称参数通常也可以以任何顺序给出,并且参数可以是可选的。如此相似,是的,但根本不同。
Caleb

2
我在想蟒蛇: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

答:小道消息

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

我相信您正在寻找被称为“ 流畅接口(我特此在@answers上发表评论,最初由@Jesper提出)的抽象”)。现在,这种常见模式已经成功用多种语言实现,其中Objective-C只是其中一种。

这是一个非常干净的示例:

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

您可以在Randy Patterson的如何设计流畅的界面 ”中看到如何实现这样的功能

Andre Vianna简要介绍了历史,然后在另外两篇文章中讨论了可能的实现,其中包括大量有用的信息。Vianna可以追溯到我在Smalltalk 80中首次遇到的古老想法,即“ 层叠 ”,该想法可以将多个消息发送到同一对象。它看起来像这样:

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

随后,级联演变为“ 方法链接 ”,在这里我们“ 使修饰符方法返回宿主对象,以便可以在单个表达式中调用多个修饰符。 ”方法链接后来逐渐发展成为今天我们知道并经常使用的流畅接口概念。 。您打算做的事情看起来非常相似。

Ayende Rahien讨论了“流利的接口”与“方法链”之间的显着差异,以至于应得其名

流利的接口在行为驱动开发(BDD)中使用的一些新工具中很常见,甚至在其新的基于约束的断言模型中也已进入主要的.NET单元测试工具NUnit中

这些基本方法随后已用其他语言实现,包括Ruby,Python,C#,Objective-C和Java。要实现类似的功能,您将需要研究“ 闭包 ” 的概念,这对于链接和流畅性而言非常重要。

也许您可以改进这些模型;这就是我们获得出色的新语言的方式。不过,我相信,充分理解方法链接和流利的接口将为您提供一个发展思想的良好起点!


2
到目前为止,大多数研究答案都为+1,尽管添加示例并重新措辞以提高可读性可能会有所帮助。
haylem

@haylem,感谢您让我回过头来添加示例和更多细节!
John Tobler

3
已被推荐,因为它很好地描述了流利的风格,但是请注意,这确实不是OP所要求的。在我阅读本文时,这个问题涉及到将参数与单个函数或方法的名称的一部分进行散布。请注意建议的函数声明:function GetTop(x)CustomersOfTheYear(y)。这是一个函数,而不是对两个不同函数的链接调用。
Caleb

@Caleb我认为他在这里试图指出这些infix参数是流利的界面(此答案)或命名参数(另一个答案)的不灵活的方法。 到目前为止,我还没有看到对他们的任何好处,即流畅的接口/命名参数不能做得更好。
Izkata 2014年

16

Objective-C做到了。这是一个典型的原型:

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

这是调用这种方法的方式:

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

Objective-C主要用于Mac OS X的Cocoa和iOS的Cocoa Touch,但是gcc会在gcc可以使用的几乎所有平台上构建Objective-C代码。


抱歉,子弹应该是连字符。我猜答案文本中的连字符被当作标记。Objective-C中的连字符用于声明属于对象的方法-[foo bar:x],其中foo是对象或类实例-而加号用于类方法,C ++称为静态成员函数。
Mike Crawford

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链接非常相​​似。我对吗?
2011年

是的,@ Saeed,jQuery使用此样式。
Karl Bielefeldt

5

Python具有关键字参数。函数定义示例

def getTopCustomers(count,year):
...

函数调用示例

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

(我理解这并不是原始问题的实质,但是如果lisp中的关键字参数符合条件,那么也可以这样做。但是,在Smalltalk和Objective-C中,参数之间的关键字实际上是函数名称/查找的一部分)


我个人更喜欢这种方式,因为如果您知道参数的顺序,这使您可以选择不带参数名称的函数调用
Pablo Mescher 2013年


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!)。


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

1
+1是因为这很有趣,但是请记住top20Func中的'20'不再是参数,而是使您想起该参数的名称的一部分。您可以轻松地说:var top5Func = getTopCustomersFunc(37);。此处的'5'具有误导性,但是代码的工作原理与该变量已被命名为完全相同top37Func
Caleb

1

这取决于您对“语言”的定义,但是robotframework测试框架允许您以这种方式定义关键字。从他们关于嵌入式参数的文档中:

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

上面声明了一个名为“从列表中选择$ {animal}”的新关键字(本质上是一个函数),其中“ $ {animal}”是一个参数。您称其为“从列表中选择猫”


在我看来,这就像SQL语句。+1
Saeed Neamati 2011年

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语言,因此无法将参数与调用或其在代码其他区域的用法区分开。

我对这种语言很感兴趣。仅使用未经详细说明的代码示例,答案就很短,但是OP给出的示例也是如此(尽管使用的是更传统的语言)。Wiki有一篇不错的文章可供阅读。
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

但是要注意的一件事是,条款fromat并没有强制执行。那里一定有东西,完全跳过它们是一个错误,但是由于宏最终只会丢弃它们,因此超出可读性的内容无关紧要(这很重要):

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

-2

在Clojure中,通常在以下情况下使用关键字参数,例如:

(get-customers :top 50 :year 2010)

关键字参数非常灵活,它们可以是可选的,并指定了默认值等。


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

1
第二个示例中的语法错误。另外,已经有人张贴了这个。
温斯顿·埃韦特

这只是重复了(在更好的解释中)的观点 在此之前的回答这是发表于3年前
蚊蚋
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.