Gli oggetti possono essere implementati in termini di funzioni di ordine superiore?

6

Martin Odersky ha terminato un corso online su Scala con una domanda senza risposta:

Possiamo implementare un concetto in termini di altro?

  • Oggetti in termini di funzioni di ordine superiore?
  • Funzioni di ordine superiore in termini di oggetti?

È chiaro che le funzioni di alto ordine possono essere implementate usando gli oggetti, ma non sono sicuro che funzioni al contrario o almeno durante l'utilizzo di tipi statici.

Supponiamo che la chiusura possa contenere dati incapsulati come fa l'oggetto ma ha ancora un solo 'metodo' nella sua interfaccia - applicandosi. Nei linguaggi dinamici (o in quelli statici se usiamo un tipo ampio come Object o Any ) possiamo passare e restituire qualsiasi cosa da questa funzione, ma questo è davvero un oggetto?

    
posta Arkonix 26.12.2015 - 14:47
fonte

4 risposte

8

Con la digitazione dinamica, è abbastanza semplice implementare un sistema orientato agli oggetti in termini di chiusure. Ho scritto su questo in la mia risposta a "Modellazione di oggetti come funzioni" e espanso su quello sul mio blog . Ci sono alcuni dettagli su aprire la ricorsione che sono necessari per ottenere certe funzionalità di OOP come la sottoclasse giusta, ma è fattibile. In breve, invocare la chiusura che rappresenta un oggetto associa un nome di metodo a un metodo associato a quell'oggetto, che può quindi essere invocato come una funzione ordinaria. L'utilizzo potrebbe essere simile a result = object("methodName")(otherObject) .

Tuttavia, OOP e tipizzazione statica sono fondamentalmente in disaccordo. Esistono varie interpretazioni di OOP, come OOP-come-message-passing o OOP-as-virtual-dispatch, ma un tema centrale è che non conosciamo staticamente il tipo esatto di runtime di un'espressione come x . Tuttavia, molti linguaggi OOP con tipizzazione statica assegnano limiti di tipo a un'espressione (ad esempio x è un sottotipo di Iterable ). Quando si implementano gli oggetti in termini di chiusure in un linguaggio tipizzato in modo statico, si verifica rapidamente il problema: quando si specifica il metodo richiesto come argomento della funzione di invio, non è possibile conoscere staticamente la firma richiesta della funzione. Nell'esempio sopra, come faccio a sapere che il risultato di object("methodName") dovrebbe essere una funzione che accetta esattamente un parametro?

La soluzione comune quando si implementano oggetti è rendere l'oggetto-sistema unificato (alias, non tipizzato). Cioè, tutte le firme dei metodi avrebbero lo stesso tipo indipendentemente dalla loro arità (numero di argomenti) o dai tipi di argomenti. Ciò richiede anche che tutti i nostri oggetti abbiano lo stesso tipo nella lingua host.

Alcune lingue potrebbero essere in grado di fare meglio. Per esempio. in C ++, potremmo passare il tipo di metodo richiesto come parametro del modello alla funzione di invio: auto result = object<ResultType(ArgumentType)>("methodName")(otherObject) . Un'implementazione intelligente potrebbe quindi utilizzare diverse tabelle di ricerca per inviare int() o int(int) tipi di metodo, ecc. Tuttavia, non possiamo garantire staticamente che il metodo richiesto esista poiché è fornito come una stringa. Un'altra possibilità sarebbe quella di passare in un oggetto simile a "visitor-like?" Message anziché a un nome di stringa alla funzione di invio, che potrebbe consentire più sicurezza di tipo nelle lingue host tipizzate staticamente, ma non ho esperienza sufficiente con l'implementazione di OOP in linguaggi statici per descrivere questo in modo più dettagliato.

    
risposta data 26.12.2015 - 15:46
fonte
1

In modo efficace, yes . Chiusure e oggetti sono equivalenti. Le funzioni di ordine superiore sono un po 'più discutibili. Senza chiusura su variabili locali (o se le variabili locali sono immutabili nella tua lingua), non ci possono essere campi mutabili nello pseudo-oggetto. Se puoi ottenere solo oggetti di ordinamento immutabili, allora è più facile sostenere che non sono come oggetti.

Ma da un punto di vista concettuale , dovresti generalmente pensare a chiusure e oggetti come bestie simili. Ad esempio, in C #, le chiusure sono implementate tramite le classi. Mi aspetto che Scala faccia lo stesso.

    
risposta data 26.12.2015 - 15:27
fonte
1

Si può pensare a un oggetto come a una chiusura che si chiude sulle variabili membro dell'oggetto e, ogni volta che viene richiamato con un nome di metodo, restituisce un'implementazione di metodo. È quindi possibile applicare l'implementazione del metodo restituito sugli argomenti del metodo effettivo.

Poiché il risultato di questa chiusura è una procedura / funzione (un'implementazione del metodo), è effettivamente una funzione di ordine superiore: una funzione di ordine superiore è una funzione che prende funzioni come argomenti di input o restituisce una funzione come risultato.

    
risposta data 26.12.2015 - 15:44
fonte
0

Dal punto di vista della programmazione funzionale, gli "oggetti" hanno un aspetto sostanzialmente simile a questo:

  1. Registra i tipi, con un campo per ogni metodo o campo pubblico;
  2. I valori della maggior parte di questi campi sono procedure di prima classe;
  3. Tutte le procedure in un oggetto sono chiusure che hanno lo scopo sugli stessi binding privati.

Quindi, detto questo, passiamo alla tua confusione:

Suppose that closure can contain encapsulated data as object does but it still has only one 'method' in its interface - applying itself.

La parte che manca qui è la mia # 1, la parte sui tipi di record. Direi che dovresti considerarlo in questi termini: i linguaggi OOP sono progettati con un costrutto, la classe , che amalgama i tipi di record e . Nei linguaggi funzionali questi sono generalmente trattati come caratteristiche ortogonali.

In dynamic languages (or in static ones if we use some broad type like Object or Any) we can pass and return anything from this function but is this really an object?

A volte le persone traducono l'idea OOP (irrimediabilmente vaga) di "passaggio di messaggi" in questi termini:

  1. I messaggi sono quindi stati modellati esplicitamente come valori. (I tipi di unione tag / case class sono eccellenti per questo.)
  2. Un oggetto, quindi, è un valore la cui operazione principale è accettare i messaggi e rispondere ad essi.

Ma direi che questo, visto da un obiettivo di programmazione funzionale, è fondamentalmente una versione degenerata del modello dell'interprete.

    
risposta data 28.12.2015 - 19:58
fonte

Leggi altre domande sui tag