2009-09-13 15 views
10

Sto cercando LINQ e il linguaggio di query appare (almeno in superficie) per essere nient'altro che un'implementazione di mappe e/o list comprehensions come si trova in Haskell e in altri linguaggi FP (in particolare la generalizzazione di 'mappa') e 'per' in Scala). È corretto? C'è altro nella sintassi di questo? Dal tono senza respiro del libro che sto leggendo ("Essential LINQ") sembrerebbe che ci sia qualcosa di nuovo o innovativo qui.Quanto c'è a LINQ?

C'è tutto il back-end, la pipeline, alberi di espressione del primo ordine e tipi ecc per implementare LINQ ma la mia domanda riguarda il linguaggio di query stesso.

Acclamazioni

Joe

risposta

25

Funzionalmente parlato, LINQ non è altro che una semplificazione sintattica dell'espressione delle monadi. Linq to Objects (List-comprehensions - anche questo sarebbe già estremamente utile), di cui hai parlato, è solo una possibile applicazione (simile alla List-Monad in Haskell).

Se si scrive

from x in expr1 
from y in expr2 
select x + y 

non è niente, ma

do 
    x <- expr1 
    y <- expr2 
    return $ x + y 

in Haskell.

La cosa concreta che viene fatto dipende LINQ provider definiti dall'utente (Interne-metodi) di cui Linq.Enumerable è solo una realizzazione che coinvolge IEnumerable s.

Fornendone uno, puoi creare semantica LINQ completamente nuova per i tuoi tipi.

Esempio: Dato un tipo Option per calcoli che potrebbero non riuscire (valori nullable), è possibile definire un provider Linq per eseguire una query su di essi.

public static class MaybeExtensions 
{ 
public static Option<T> ToMaybe<T>(this T value) 
{ 
    return Option<T>.Some(value); 
} 

public static Option<U> SelectMany<T, U>(
    this Option<T> m, 
    Func<T, Option<U>> k) 
{ 
    return !m.IsNone ? Option<U>.None : k(m.Value); 
} 

public static Option<V> SelectMany<T, U, V>(
    this Option<T> m, 
    Func<T, Option<U>> k, 
    Func<T, U, V> s) 
{ 
    return m.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe())); 
} 
} 

Ciò consentirà ora di scrivere questo codice:

var sum = from x in ReadNumber("x") 
      from y in ReadNumber("y") 
      select x + y; 

Il calcolo restituisce solo un valore se tutti i calcoli sono riusciti a pena non riuscire al primo in mancanza di uno.

In combinazione con alberi di espressione, LINQ può essere estremamente potente e permette di esprimere -

  1. accessi al database
  2. flusso programma Asynchronous
  3. maybe-Monadi
  4. di lista
  5. ricorsivo parser di discesa
  6. Continuazioni
  7. Mini-lingue
  8. calcoli paralleli (PLINQ)

alcuni link:

Combinato con combinatori a virgola fissa, Linq fornisce un mini-linguaggio funzionale completo (Linq raytracer).

noti che Scala e F # entrambi hanno concetti simili a for-comprensioni e le espressioni di calcolo essendo entrambi astrazioni monadici:

Scala:

for (x <- expr1 
    y <- expr2) yield x + y 

F #:

monad { 
    let! x = expr1 
    let! y = expr2 
    return x + y 
} 
+0

Grazie per le informazioni. Guarderò quei cavi. – Joe

+0

Davvero, davvero un buon riassunto con un esempio piacevole e di facile comprensione. +1 –

+0

Continuando sul collegamento raytracer, ecco lo stesso raytracer implementato interamente in una singola istruzione LINQ: http://tirania.org/blog/archive/2007/Nov-16.html – JulianR

4

Oltre a leggere un libro su di esso, hai già utilizzato LINQ? Ho trovato un enorme risparmio di tempo nel mio lavoro quotidiano di programmazione. Per me, è il prossimo passo dell'astrazione, che può essere utilizzato per combinare diverse origini dati come XML o SQL e lavorare con loro nello stesso "linguaggio".

Inoltre, raccomando questo interview with Anders Hejlsberg sulla programmazione funzionale e LINQ.

+0

Grazie per la risposta e il collegamento, lo leggerò. Sì, l'ho usato un po '(e lo trovo davvero molto utile), ma l'ho usato nello stesso modo in cui ho usato la mappa e in Scala. Ho fatto la domanda a causa delle somiglianze e mi sono chiesto quanto in profondità andassero. – Joe

5

L'affanno è probabilmente destinato a tutto ciò che è "ovvio", alcuni dei quali (come gli alberi di espressione) sono davvero eccellenti. La lingua è solo un mezzo di accesso; ti eccita la parola chiave throw o la funzionalità che espone?

+0

Non intendevo che l '"ovvia" roba fosse ovvia, semplicemente che era stata riconosciuta ma non al centro della mia domanda! Forse l'ho descritto un po 'male. – Joe

+0

Altri, per favore, leggi il commento di Ben M alla luce della mia modifica alla domanda. – Joe

2

LINQ è stato ispirato di HaskellDB, come lo ha affermato il numero Erik Meijer, ad es in Confessions of a Used Programming Language Salesman (Getting the Masses Hooked on Haskell), quindi non è di per sé un nuovo concetto. L'uso della stessa lingua per interrogare fonti diverse è in una certa misura innovativo, sebbene il fatto che il modello relazionale annidato copra XML, oggetti e database relazionali è stato dimostrato dai ricercatori in precedenza. Per me, ciò che è estremamente interessante è che è stato incorporato in un linguaggio popolare, generale e principalmente orientato agli oggetti, che non è mai stato fatto prima.

Scala IMHO ha le capacità per incorporare qualcosa di simile. Finora, per Scala abbiamo Stefan Zeiger's ScalaQuery e Daniel Spiewak 's ScalaQL, che seguono le orme LINQ.

+0

Grazie per i collegamenti, sembrano molto interessante. – Joe

3

Il nucleo di LINQ, la sintassi della query, non è in realtà di enorme portata.Si tratta semplicemente di alcuni molto letterale traduzioni, ai metodi e lambda - così

var qry = from x in src 
      where x.Foo == "foo" 
      select x.Bar; 

è letteralmente:

var qry = src.Where(x => x.Foo == "foo").Select(x => x.Bar); 

Si sa nulla di metodi di estensione (anche se sono il più comune (ma non solo implementazione), e nulla su Expression ecc. Il numero di parole chiave (e quindi il numero di implementazioni del metodo richieste) non è enorme. Jon una volta tentato di implementare tutti in un'ora (in una presentazione dal vivo). Non ha fatto troppo male ;-P


Forse la parte più impressionante di LINQ è l'espressione albero supporto che è stato necessario per consentire LINQ da utilizzare contro le basi di dati - vale a dire l'espressione lambda che può essere compilato o a un delegato o in un modello a oggetti che rappresenta il codice scritto. È interessante notare che questa stessa idea traspare dal modo in cui la risoluzione DLR funziona in 4.0.

+0

Una prospettiva molto utile. Grazie per il chiarimento. – Joe