2010-07-22 11 views
9

Mi chiedevo, c'è qualche linguaggio di programmazione in cui si può avere funzione di chiamate in questo modo:Qualsiasi linguaggio di programmazione con chiamata di funzione "strana"?

function_name(parameter1)function_name_continued(parameter2); 

o

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

Per esempio si potrebbe avere questa funzione di chiamata:

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

se è stata definita la funzione distanceFromto in questo modo:

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

Per quanto ne so, nei linguaggi di programmazione C, Java e SML, questo non può essere fatto.

Sei a conoscenza di un linguaggio di programmazione che consente di definire e chiamare le funzioni in questo modo?

+1

Potresti essere un po 'più esplicito su cosa potrebbe comportare? – nos

+1

Beh, penso che alcune chiamate di funzione siano molto più facili da leggere come l'esempio 'distanceFromto'. Ma ero solo curioso di sapere se esiste un tale linguaggio di programmazione che consente di definire tale funzione. –

+0

Penso che sia necessario un esempio migliore per illustrare cosa si sta tentando di dire perché il passaggio di più valori in una funzione ottiene la stessa cosa ed è altrettanto (se non più) chiaro. PER ESEMPIO. dist = distanceFrom (cityA, cityB) –

risposta

6

E sembra un sacco come Objective-C

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

Grazie per la risposta. Immagino che il codice che hai scritto sia la definizione della funzione. Potresti anche dare un esempio di come viene chiamata questa funzione? –

+0

Quasi identicamente a Smalltalk: dist = [distanza metricaDa: cittàA a: cittàB]; –

6

Suona un po 'come la sintassi di Smalltalk, (il che spiegherebbe la sintassi di Objective-C - vedere la risposta di Kubi).

Esempio:

dist := metric distanceFrom: cityA to: cityB 

dove #distanceFrom: a: ​​è un metodo su un oggetto chiamato metrica.

in modo da avere "chiamate di funzione" (sono davvero messaggio invia) come

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

EDIT: avevo detto "Davvero, #distanceFrom: a: ​​dovrebbe essere chiamato #distanceTo: su una città classe, ma comunque. " Justice indica che questo accoppia una città a una metrica, che è cattiva. Ci sono buone ragioni per cui potresti voler variare la metrica - gli aeroplani potrebbero usare una geodetica mentre le auto potrebbero usare un percorso più breve basato sulla rete stradale.)

+1

Una metrica è una 'strategia' per misurare la distanza tra due punti. Esistono più strategie valide che restituiscono risultati validi diversi. 'metriC# distanceFrom: to' è la tecnica giusta; 'city # distanceTo' è nella migliore delle ipotesi un'approssimazione. Che cosa sanno alle città le distanze da altre città ?! Le città conoscono le loro posizioni e le metriche sanno come misurare le distanze tra due posizioni. – yfeldblum

+0

Giustizia, hai ragione.Mi piace '#distanceTo:' perché è breve - ma questo è un compromesso che probabilmente non vale la pena di fare, perché aumenta l'accoppiamento (le città conoscono le cose non-City) e non è molto più breve di '#distanceFrom: to:'. Grazie! –

0

Questo è simile all'overloading di funzione (C++/C#)/parametri di default (VB).

parametri predefiniti consentono alla persona che definisce la funzione per impostare i valori predefiniti per questi ultimi parametri:

esempio 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

È possibile utilizzare una funzione membro per questo.

cityA.distance_to(cityB); 

Questo è codice valido in C++, C (con un piccolo ritocco), C#, Java.Utilizzando catene di metodo, si può fare:

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

In Python, è possibile passare in modo esplicito il nome degli argomenti che si sta chiamando la funzione con, che consente di li passa in un ordine diverso o saltare argomenti opzionali:

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

Questo assomiglia molto a ciò che la sintassi dell'Objective C sta facendo, taggando ogni argomento con una funzione con il suo nome.

2

(vedi il mio impegno personale molto favorito - l'avvicinamento finale C++ alla fine di questa risposta)

Lingua Uno

Objective-C, ma la sintassi di chiamata è [messaggio oggetto] così apparirebbe come:

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

se hai definito distanceFromto funzione come questa, entro una città oggetto:

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

Lingua Due

Ho anche il sospetto che si potrebbe ottenere qualcosa di molto vicino a questo nel IO Language ma sto solo solo a guardarla. Si consiglia inoltre di leggere su di esso in confronto ad altre lingue in Seven Languages in Seven Weeks che ha un free excerpt su IO.

Lingua Tre

C'è un idioma ("concatenamento") in C++ in cui si ritorna oggetti temporanei o l'oggetto corrente che viene utilizzato per sostituire argomenti a parola chiave, secondo The Design and Evolution of C++ e si presenta così:

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

se è stata definita la funzione distanceFrom in questo modo, con un piccolo oggetto di supporto. Nota che le funzioni inline rendono questo tipo di cosa compilare codice molto efficiente.

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, ero di fretta in precedenza, sono reso conto che posso refactoring di utilizzare solo un oggetto temporaneo per dare la stessa sintassi:

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 ed ecco un ancora più ispirato versione C++ che permette di scrivere

int dist = distanceFrom cityA to cityB; 

o addirittura

int dist = distanceFrom cityA to cityB to cityC; 

sulla base di una combinazione meravigliosamente C++ ish di #define e classi:

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

NOTA questo può sembrare un esercizio inutile, ma in alcuni contesti può essere molto utile per dare alla gente un dominio -specific language in C++ che compilano insieme alle librerie. Abbiamo utilizzato un approccio simile con Python per gli scienziati di geo-modellizzazione presso il CSIRO.

+0

Non ho conoscenza del C++ ma l'assegnazione: 'int dist = distanceFrom cityA to cityB;' sembra pulito! Grazie per aver dedicato del tempo a rispondere alla mia domanda. –

+3

È questa intelligenza su C++ che mi fa sempre sorridere e rabbrividire contemporaneamente. – Novelocrat

0

In SML è possibile semplicemente impostare "su" un valore (unità, ad esempio) e "distanzaDa" di una funzione al curry che richiede tre parametri. Per esempio:

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

val foo = distanceFrom cityA to cityB 

si potrebbe anche approfittare del fatto che SML non applica le convenzioni di denominazione di costruttori datataype (con grande disappunto molti popoli), quindi se si vuole fare in modo che le fa rispettare tipo di sistema la sintassi personalizzato:

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

Anche se non stavo cercando una funzione al curry. Ho trovato davvero interessante e bello il trucco che hai fatto con 'datatype comp = to' :) (+1 per questo) –

2

C# 4.0 di funzione Named and Optional Arguments consente di ottenere qualcosa di molto simile:

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

Che assomiglia molto ai parametri delle parole chiave di Common Lisp, è spaventoso: (distanza da:" New York "a:" Tokyo ") –

+0

Le parole chiave iniziano con': ', non finisce con esso, quindi sarebbe' (distanza: da "New York": a "Tokyo") '. Ma si. – Ken

+0

Python ha anche argomenti per parole chiave. – Novelocrat

4

per i curiosi, Agda2 ha una simile, sintassi molto permissiva. Quello che segue è codice valido:

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 

Se

from Paris to London 

viene valutata, il risultato è

342 km 
0

Si potrebbe fare questo in Scheme o LISP usando le macro.

Il modulo sarà qualcosa di simile:

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

I simboli in maiuscolo denota sintassi.

Si potrebbe anche fare qualcosa di simile 'parametri denominati':

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

È anche possibile farlo con il preprocessore C ... – reinierpost

+0

Si potrebbe tranquillamente avere (distanza: da 'città-a: a' città-b) con questo: (distanza defun (e chiave da a) ...) (ma questo non affronta la domanda, perché la funzione è ancora chiamata DISTANZA). –

+0

@reinierpost come si può fare con il preprocessore C? –

0

Tcl ti permette di fare qualcosa di simile:

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

non sono sicuro se questo è proprio quello che si sta pensando di però.

1

Si può fare questo in C, anche se non sicuro:

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 = 

utilizza compound literals e designated initializers.

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

+1 per essere un po 'complicato –

+1

È come dice il proverbio: solo perché puoi, non significa che dovresti. –

0

È possibile farlo in Java, Usa Builder pattern che appare nel libro Effective Java da Joshua Bosch (questa è la seconda volta che ho messo questo link nel SO, io ancora non ho usato che patern, ma sembra fantastico)

0

Bene, in Felix puoi implementarlo in due passaggi: in primo luogo, scrivi una funzione ordinaria. Quindi, puoi estendere la grammatica e mappare alcuni dei nuovi non-terminali alla funzione.

Questo è un po 'pesante rispetto a quello che si potrebbe desiderare (benvenuto per aiutare a rendere più facile !!) Penso che questo faccia ciò che vuoi e molto di più!

darò un esempio reale perché il tutta della lingua Felix è effettivamente definita da questa tecnica (sotto x è il non terminale per le espressioni, il p in x [p] è un codice precedenza):

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

Ecco un po 'di più:

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

La grammatica Felix è codice utente ordinario. Negli esempi le azioni grammaticali sono scritte in Scheme. La grammatica è GLR. Permette "parole chiave sensibili al contesto", cioè identificatori che sono parole chiave solo in determinati contesti, il che rende facile inventare nuovi costrutti senza preoccuparsi di rompere il codice esistente.

Forse si desidera esaminare Felix Grammar Online.

Problemi correlati