簡體   English   中英

任何帶有“奇怪”函數調用的編程語言?

[英]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"]

我不確定這是不是你想到的。

你可以用Java ,Use Builder模式來實現它,這個模式出現在Joshua Bosch的書籍Effective Java中 (這是我第二次將這個鏈接放在SO中,我仍然沒有使用那個模式,但看起來很棒)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM