Perché "zip" ignora la coda ciondolante della collezione?

11

C # , Scala, Haskell, Lisp e Python hanno lo stesso comportamento zip : se una raccolta è più lunga, la coda è silenziosa ignorato.

Potrebbe anche essere un'eccezione generata, ma non ho sentito parlare di alcun linguaggio utilizzando questo approccio.

Questo mi imbarazza. Qualcuno conosce il motivo per cui zip è stato progettato in questo modo? Immagino per le nuove lingue, è fatto perché le altre lingue lo fanno in questo modo. Ma quale era il motivo principale?

Sto ponendo qui una domanda basata sui fatti, storica, non se a qualcuno piace, o se è un approccio buono o cattivo.

Aggiornamento : se mi venisse chiesto cosa fare, direi - lanciare un'eccezione, in modo abbastanza simile all'indicizzazione di un array (nonostante le "vecchie" lingue abbiano fatto ogni tipo di magia, come gestire fuori limite indice, UB, espansione array, ecc.)

    
posta greenoldman 02.03.2015 - 18:19
fonte

2 risposte

10

È quasi sempre quello che vuoi, e quando non lo è, puoi farlo da solo.

Il problema principale è con la semantica pigra che non conosci la lunghezza quando avvii per la prima volta zip , quindi non puoi lanciare un'eccezione all'inizio. Dovresti prima restituire tutti gli elementi comuni, quindi generare un'eccezione, che non sarebbe molto utile.

È anche un problema di stile. I programmatori imperativi sono abituati a controllare manualmente le condizioni al contorno dappertutto. I programmatori funzionali preferiscono i costrutti che non possono fallire in base alla progettazione. Le eccezioni sono estremamente rare. Se c'è un modo per una funzione di restituire un valore ragionevole, i programmatori funzionali lo prenderanno. La componibilità è il re.

    
risposta data 02.03.2015 - 22:03
fonte
11

Perché non c'è un modo ovvio per completare la coda. Qualsiasi scelta su come farlo si tradurrebbe in una coda non ovvia.

Il trucco è di allungare esplicitamente la tua lista più breve per abbinare la lunghezza del più lungo con i valori che ti aspetti.

Se zip lo facesse per te, non potevi sapere quali valori stava compilando in modo intuitivo. Ha ciclato la lista? Ha ripetuto un valore mempty? Cos'è un valore mempty per il tuo tipo?

Non c'è alcuna implicazione in ciò che zip può usare per intuire il modo in cui la coda verrebbe estesa, quindi l'unica cosa ragionevole da fare è lavorare con i valori disponibili piuttosto che fare in modo che il consumatore non si aspetti.

Ricorda anche che ti stai riferendo a una funzione ben nota molto specifica con una semantica ben nota. Ma ciò non significa che non puoi creare una funzione simile ma leggermente diversa . Solo perché esiste una funzione comune che fa x , non significa che non puoi decidere per il tuo scopo specifico che vuoi fare x e y .

Pur ricordando la ragione per cui questa e molte altre comuni funzioni di stile FP sono comuni, è perché sono semplici e generalizzate, quindi puoi modificare il codice per usarle e ottenere il comportamento che desideri. Ad esempio, in C # potresti solo

IEnumerable<Tuple<T, U>> ZipDefaults(IEnumerable<T> first, IEnumerable<U> second)
{
    return first.Count() < second.Count()
        ? first.Concat(Enumerable.Repeat(default(T), second.Count() - first.Count())).Zip(second)
        : first.Zip(second.Concat(Enumerable.Repeat(default(U), first.Count() - second.count())))
}

O altre semplici cose. Gli approcci FP rendono le modifiche così semplici perché puoi riutilizzare i pezzi e avere implementazioni così piccole come sopra che creare le tue versioni modificate delle cose è estremamente semplice.

    
risposta data 02.03.2015 - 18:33
fonte

Leggi altre domande sui tag