Esiste una lingua in cui le raccolte possono essere utilizzate come oggetti senza alterare il comportamento?

7

Esiste una lingua in cui collezioni può essere utilizzato come oggetti senza alterare il comportamento?

Ad esempio, per prima cosa, immagina queste funzioni funzionanti:

function capitalize(str) 
    //suppose this *modifies* a string object capitalizing it
function greet(person):
    print("Hello, " + person)

capitalize("pedro")
>> "Pedro"

greet("Pedro")
>> "Hello, Pedro"

Ora, supponiamo di definire una raccolta standard con alcune stringhe:

people = ["ed","steve","john"]

Quindi, chiamerà toUtilizzatore () su ciascun oggetto su quell'elenco

people.toUpper() 
>> ["Ed","Steve","John"]

E questo chiamerà saluti una volta per OGNI persona sulla lista, invece di inviare l'elenco come argomento

greet(people)
>> "Hello, Ed"
>> "Hello, Steve"
>> "Hello, John"
    
posta MaiaVictor 03.06.2012 - 23:33
fonte

3 risposte

21

Sì, ci sono tali lingue. Molti di loro.

In effetti, questa funzione è praticamente la definizione di un linguaggio di array o linguaggio vettoriale . Esempi di linguaggi array e vettoriali includono, ma non sono limitati a, la famiglia di linguaggi APL con i suoi successori, derivati e cugini (ad esempio APL, J, K) e praticamente tutti i linguaggi matematici e statistici come Mathematica, MATLAB, Octave, R e S.

Anche Fortran 90 e Ada hanno questa caratteristica, così come Fortress.

È interessante notare che molte CPU moderne supportano anche la programmazione vettoriale, ad es. l'architettura x86 con MMX, SSE, SSE2, SSE3 (Intel) e 3DNow! (AMD) set di istruzioni, le architetture POWER e PowerPC con i set di istruzioni VMX e AltiVec, Sparc, MIPS, anche ARM.

La lingua di Microsoft Research ha il concetto di stream (più o meno simile a IEnumerable ). Gli stream funzionano praticamente esattamente come tu descrivi. Ecco un esempio della documentazione di Cω (enfasi mia):

A key programming feature of Cω is generalized member access: the familiar 'dot' operator is now much more powerful. Thus if the receiver is a stream, then the member access is mapped over the elements, e.g. zones.ToString() implicitly maps the method call over the elements of the stream zones and returns a value of type string*. This feature significantly reduces the burden on the programmer.

Una proprietà molto interessante di questo tipo di programmazione è che non solo consente di pensare semanticamente di "applicare un'operazione a tutti gli elementi contemporaneamente", ma consente anche all'implementatore della lingua di implementalo con letteralmente applicando un'operazione a tutti gli elementi in una volta , IOW in parallelo .

    
risposta data 04.06.2012 - 05:42
fonte
1

Puoi ottenere una semantica molto simile a quella che stai chiedendo in quasi tutte le lingue usando il pattern composito.

Dato che hai un tipo simile a questo:

// pseudocode
class CustomString
{
    CustomString Composite;
    string Value;
}

... e un metodo Greet come questo:

// pseudocode
public string Greet(CustomString cs)
{
    string ret;
    if (cs!= null)
        ret += "Hello " + cs.Value + newline;

    if (cs.Composite != null)
        ret += Greet(cs.Composite);
}

... puoi effettuare chiamate in questo modo:

writeln(Greet(new CustomString("snorfys")))
>> Hello snorfys

cs = new CustomString("snorfys") { Composite = new CustomString("Dokkat") }
writeln(Greet(cs))
>> Hello snorfys
>> Hello Dokkat

Se si lavora molto con gli alberi, la programmazione in questo modo si avverte rapidamente (ovvero, ogni nodo dell'albero è, e può essere trattato come, una sottostruttura).

    
risposta data 04.06.2012 - 06:09
fonte
1

In C #, ad esempio, ci sono estensioni (aggiungi la funzionalità alla raccolta - al di sotto sarebbe ancora un ciclo, ma non visibile) e Linq - esempio:

public static IEnumerble<string> Capitalize(this IEnumerable<string> collection)
{
   var List<string> rtn = new List<string>(collection.Count());
   foreach (var item in collection) 
   {
      var ci = Thread.CurrentThread.CurrentCulture; 
      var textInfo = ci.TextInfo; 

      rtn.Add(textInfo.ToTitleCase(item)); 
   }
   return rtn;
}

[Nota: ho digitato questo tasto, quindi forse alcuni errori di battitura]

in alternativa, ...

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{  
   source.ThrowIfNull("source");     
   action.ThrowIfNull("action");    
   foreach (T element in source)    
   {         
        action(element);     
   } 
} 

con una funzione per capitalizzare

public static string Capitalize(this string str)
{
    var ci = Thread.CurrentThread.CurrentCulture; 
    var textInfo = ci.TextInfo; 

    return textInfo.ToTitleCase(str); 
 }

e poi

myColl.ForEach(x => x.Capitalize()); 

La differenza è il secondo consente di passare qualsiasi funzione e per qualsiasi tipo di raccolta.

myCollection.Where(employee => emplyee.Age > 50).ForEach(employee => employee.Fire());

funziona anche (in un modo senza cuore: D)

    
risposta data 04.06.2012 - 13:43
fonte