[英]Any programming language with “strange” function call?
我想知道,是否有任何編程語言可以讓你有這樣的函數調用:
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編程語言中,這是不可能完成的。
您是否了解任何編程語言,您可以通過這種方式定義和調用函數?
它看起來很像Objective-C
- (int)distanceFrom:(City *)cityA to:(City *)cityB {
// woah!
}
聽起來很像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:應該叫做#distanceTo:在城市課上,但無論如何。” Justice指出,這將城市與公制聯系起來,這是一個壞的。 您可能想要改變度量標准有很好的理由 - 飛機可能使用測地線,而汽車可能會使用基於道路網絡的最短路徑。)
對於好奇的人來說,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
在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語法正在做的事情,用函數標記函數的每個參數。
(請參閱我最喜歡的個人努力 - 本答案結尾處的最終C ++方法)
語言一
Objective-C但調用語法是[object message],所以看起來像:
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;
}
語言二
我也懷疑你可以在IO語言中實現與此非常接近的東西,但我只是在看它。 您可能還想閱讀它與Seven Weeks七種語言中的其他語言相比較,其中包含有關IO的免費摘錄 。
語言三
根據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);
}
Duhh,我之前很匆忙,意識到我可以重構只是使用一個臨時對象來提供相同的語法:
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 ++ ish組合#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;
};
注意這可能看起來像一個無用的練習,但在某些情況下,為人們提供C ++中與域庫相關的特定領域語言非常有用。 我們在CSIRO對地理建模科學家采用了類似的Python方法。
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中執行此操作,盡管不安全:
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
這類似於函數重載(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)
}
您可以使用成員函數。
cityA.distance_to(cityB);
這是C ++中的有效代碼,C(稍微調整一下),C#,Java。 使用方法鏈,您可以:
cityA.something(cityB).something(cityC).something(cityD).something(cityE);
在SML中,你可以簡單地使“to”某個值(例如,unit)和“distanceFrom”一個帶有三個參數的curried函數。 例如:
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! *)
您可以使用宏在Scheme或LISP中執行此操作。
表單將是這樣的:
(DISTANCE-FROM city-a TO city-b)
大寫的符號表示語法。
你甚至可以做'命名參數'之類的事情:
(DISTANCE TO city-a FROM city-b)
(DISTANCE FROM city-a TO city-b)
Tcl允許你做這樣的事情:
proc distance {from cityA to cityB} {...}
set distance [distance from "Chicago IL" to "Tulsa OK"]
我不確定這是不是你想到的。
RemObjects在其元素編譯器中的4種聯盟語言中的3種恰好具有OP所要求的語法(支持Objective-C運行時,但可供所有操作系統使用)。
在Hydrogene(擴展的C#) https://docs.elementscompiler.com/Hydrogene/LanguageExtensions/MultiPartMethodNames
in Iodine(擴展Java) https://docs.elementscompiler.com/Iodine/LanguageExtensions/MultiPartMethodNames
在Oxygene(擴展的ObjectPascal)中,向下滾動到多部分方法名稱部分https://docs.elementscompiler.com/Oxygene/Members/Methods
好吧,在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 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.