2010-07-22 17 views
9

tôi đã tự hỏi, liệu có bất kỳ ngôn ngữ lập trình mà bạn có thể có chức năng gọi như thế này:Bất kỳ ngôn ngữ lập trình nào có chức năng gọi "lạ"?

function_name(parameter1)function_name_continued(parameter2); 

hoặc

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

Ví dụ bạn có thể có chức năng này gọi:

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

nếu bạn đã xác định distanceFromto chức năng như sau:

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

Theo như tôi biết, trong ngôn ngữ lập trình C, Java và SML, điều này không thể thực hiện được.

Bạn có biết bất kỳ ngôn ngữ lập trình nào cho phép bạn xác định và gọi các hàm theo cách này không?

+1

Bạn có thể cụ thể hơn một chút về điều này sẽ thực hiện được không? – nos

+1

Tôi nghĩ rằng một số cuộc gọi hàm sẽ dễ đọc hơn nhiều như ví dụ 'distanceFromto'. Nhưng tôi đã chỉ tò mò nếu một ngôn ngữ lập trình như vậy cho phép bạn xác định chức năng như vậy tồn tại. –

+0

Tôi nghĩ rằng bạn cần một ví dụ tốt hơn để minh họa những gì bạn đang cố gắng nói bởi vì việc chuyển nhiều giá trị vào một hàm sẽ đạt được điều tương tự và bằng nhau (nếu không rõ ràng) rõ ràng. VÍ DỤ. dist = distanceTừ (cityA, cityB) –

Trả lời

6

Nó trông giống một awful nhiều như Objective-C

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

Cảm ơn câu trả lời của bạn. Tôi đoán, mã bạn viết là định nghĩa hàm. Bạn cũng có thể đưa ra một ví dụ về cách gọi hàm này? –

+0

Hầu như giống với Smalltalk: dist = [metric distanceFrom: cityA to: cityB]; –

6

Âm thanh rất giống cú pháp Smalltalk của, (mà có thể giải thích cú pháp Objective-C - xem câu trả lời kubi của).

Ví dụ:

dist := metric distanceFrom: cityA to: cityB 

nơi #distanceFrom: đến: là một phương pháp trên một số đối tượng gọi là metric.

Vì vậy, bạn có "các cuộc gọi chức năng" (họ đang thực sự nhắn gửi) như

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

EDIT: Tôi muốn nói: "Thực sự, #distanceFrom: đến: nên được gọi là #distanceTo: trên một thành phố nhưng dù sao đi nữa. ” Justice chỉ ra rằng cặp vợ chồng này là một Thành phố thành Số liệu, đó là Xấu. Có nhiều lý do tại sao bạn có thể muốn thay đổi số liệu - máy bay có thể sử dụng đường trắc địa trong khi xe hơi có thể sử dụng đường đi ngắn nhất dựa trên mạng lưới đường.)

+1

Số liệu là một 'chiến lược' để đo khoảng cách giữa hai điểm. Có nhiều chiến lược hợp lệ, trả về các kết quả hợp lệ khác nhau. 'metriC# distanceFrom: to' là kỹ thuật đúng; 'thành phố # distanceTo' là tốt nhất một xấp xỉ. Thành phố biết gì về khoảng cách đến các thành phố khác ?! Các thành phố biết vị trí của riêng mình và số liệu biết về đo khoảng cách giữa hai vị trí. – yfeldblum

+0

Công lý, bạn nói đúng.Tôi thích '#distanceTo:' vì nó ngắn - nhưng đó là một sự cân bằng có thể không đáng làm, bởi vì nó làm tăng sự liên kết (Thành phố biết về những thứ không phải thành phố) và nó không ngắn hơn nhiều so với '#distanceFrom: to:'. Cảm ơn! –

0

Điều này trông giống như quá tải hàm (C++/C#)/tham số mặc định (VB).

Tham số mặc định cho phép người xác định hàm đặt giá trị mặc định cho tham số sau:

ví dụ: 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) 
} 
0

Bạn có thể sử dụng chức năng thành viên cho việc này.

cityA.distance_to(cityB); 

Đó là mã hợp lệ trong C++, C (với một chút tinh chỉnh), C#, Java.Sử dụng chuỗi phương pháp, bạn có thể làm:

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

Trong Python, bạn có thể vượt qua một cách rõ ràng tên của các đối số bạn đang gọi hàm với, cho phép bạn chuyển chúng theo một thứ tự khác nhau hoặc bỏ qua đối số tùy chọn:

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

Điều này trông rất giống cú pháp C mục tiêu đang làm, gắn thẻ từng đối số vào hàm có tên của nó.

2

(xem nỗ lực cá nhân rất yêu thích của tôi - C++ cách tiếp cận chính thức vào cuối câu trả lời này)

Ngôn ngữ Một

Objective-C nhưng cú pháp gọi là [nhắn đối tượng] như vậy sẽ trông như:

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

nếu bạn đã xác định distanceFromto chức năng như thế này, trong một thành phố phản đối:

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

Ngôn ngữ Hai

Tôi cũng nghi ngờ bạn có thể đạt được một cái gì đó rất gần với điều này trong IO Language nhưng tôi chỉ nhìn vào nó. Bạn cũng có thể muốn đọc về nó so với các ngôn ngữ khác trong Seven Languages in Seven Weeks có một số free excerpt về IO.

Ngôn ngữ Ba

Có một thành ngữ ("chaining") trong C++ nơi bạn trở về đối tượng tạm thời hoặc đối tượng hiện nay được sử dụng để thay thế đối số từ khóa, theo The Design and Evolution of C++ và trông như thế này:

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

nếu bạn đã xác định distanceFrom chức năng như thế này, với một đối tượng trợ giúp nhỏ. Lưu ý rằng các hàm nội tuyến làm cho loại điều này biên dịch thành mã rất hiệu quả.

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, tôi đã vội vàng trước đó, nhận ra tôi có thể cấu trúc để chỉ cần sử dụng một đối tượng tạm thời để cung cấp cho các cú pháp giống nhau:

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

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

private: 
    City* fromCity; 
}; 

My Favorite và đây là một thậm chí cảm hứng hơn Phiên bản C++ cho phép bạn viết

int dist = distanceFrom cityA to cityB; 

hoặc thậm chí

int dist = distanceFrom cityA to cityB to cityC; 

dựa trên sự kết hợp tuyệt vời C++ ish của #define và các lớp:

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

LƯU Ý này có thể trông giống như một bài tập vô dụng nhưng trong một số tình huống nó có thể rất hữu ích để cho mọi người một miền -specific language trong C++ mà chúng biên dịch cùng với các thư viện. Chúng tôi đã sử dụng cách tiếp cận tương tự với Python cho các nhà khoa học lập mô hình địa lý tại CSIRO.

+0

Tôi không có kiến ​​thức về C++ nhưng nhiệm vụ: 'int dist = distanceTừ thành phốA tới thành phốB;' có vẻ gọn gàng! Cảm ơn bạn đã dành thời gian để trả lời câu hỏi của tôi. –

+3

Đó là sự thông minh về C++ mà luôn luôn làm cho tôi mỉm cười và cringe cùng một lúc. – Novelocrat

0

Trong SML, bạn có thể chỉ cần thực hiện "thành" một số giá trị (đơn vị, ví dụ) và "distanceFrom" một hàm được thu thập có ba tham số. Ví dụ:

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

val foo = distanceFrom cityA to cityB 

Bạn cũng có thể tận dụng thực tế là SML không thực thi quy ước đặt tên trên constructors datataype (nhiều ít phiền toái của nhiều người), vì vậy nếu bạn muốn chắc chắn rằng thực thi loại hệ thống cú pháp tùy chỉnh của bạn:

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! *) 
+0

Mặc dù tôi đã không tìm kiếm một chức năng được kết hôn. Tôi thực sự thấy thú vị và tốt đẹp các trick bạn đã làm với 'datatype comp = to' :) (+1 cho điều này) –

2

C# Named and Optional Arguments tính năng 4.0 cho phép bạn để đạt được một cái gì đó khá giống nhau:

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

Điều đó trông rất giống với thông số từ khóa Common Lisp's, thật đáng sợ: (khoảng cách từ:" New York "tới:" Tokyo ") –

+0

Từ khóa bắt đầu bằng': ', không kết thúc bằng nó, vì vậy nó sẽ là' (khoảng cách: từ "New York": thành "Tokyo") '. Nhưng vâng. – Ken

+0

Python cũng có đối số từ khóa. – Novelocrat

4

Đối với người hiếu, Agda2 có một tương tự, cú pháp rất dễ chấp nhận. Sau đây là mã hợp lệ:

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 

Nếu

from Paris to London 

được đánh giá, kết quả là

342 km 
0

Bạn có thể làm điều này trong Đề án hoặc LISP sử dụng các macro.

Mẫu này sẽ được cái gì đó như:

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

Các biểu tượng trong chữ hoa biểu thị cú pháp.

Bạn thậm chí có thể làm điều gì đó như 'tên thông số':

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

Bạn cũng có thể làm điều đó với bộ tiền xử lý C ... – reinierpost

+0

Bạn có thể vui vẻ có (khoảng cách: từ 'thành phố-a: đến' thành phố-b) với điều này: (defun distance (& key from to) ...) (nhưng điều này không giải quyết được câu hỏi, bởi vì hàm vẫn được gọi là DISTANCE). –

+0

@reinierpost làm thế nào điều này có thể được thực hiện với bộ tiền xử lý C? –

0

Tcl cho phép bạn làm điều gì đó như thế này:

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

Tôi không chắc chắn nếu đó là khá những gì bạn đang nghĩ đến việc mặc dù.

1

Bạn có thể làm điều này trong C, mặc dù không an toàn:

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 = 

sử dụng compound literalsdesignated initializers.

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

+1 để trở nên phức tạp –

+1

Nó giống như câu nói: chỉ vì bạn có thể, không có nghĩa là bạn nên. –

0

Bạn có thể làm điều đó trong Java, Sử dụng Builder pattern xuất hiện trong cuốn sách Effective Java bởi Joshua Bosch (đây là lần thứ hai tôi đặt liên kết này trong SO, tôi vẫn không sử dụng patern, nhưng trông tuyệt vời)

0

Vâng, trong Felix bạn có thể thực hiện điều này theo hai bước: đầu tiên, bạn viết một hàm bình thường. Sau đó, bạn có thể mở rộng ngữ pháp và ánh xạ một số không-đầu cuối mới vào hàm.

Đây là một chút nặng so với những gì bạn có thể muốn (chào mừng để giúp làm cho nó dễ dàng hơn !!) Tôi nghĩ rằng điều này làm những gì bạn muốn và nhiều hơn cả!

tôi sẽ đưa ra một ví dụ thực tế vì toàn của ngôn ngữ Felix được xác định bằng kỹ thuật này (sau đây x là phi thiết bị đầu cuối cho các biểu thức, các p trong x [p] là một mã ưu tiên):

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

Dưới đây là thêm một chút:

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

ngữ pháp Felix là bình thường mã người dùng. Trong các ví dụ, các hành động ngữ pháp được viết trong Đề án. Ngữ pháp là GLR. Nó cho phép "các từ khóa nhạy cảm theo ngữ cảnh", nghĩa là các từ định danh trong các ngữ cảnh nhất định, giúp dễ dàng phát minh ra các cấu trúc mới mà không phải lo lắng về việc phá vỡ mã hiện có.

Có lẽ bạn muốn kiểm tra Felix Grammar Online.