... and is probably one of those articles that OOP was based on.
Non proprio, ma è stato aggiunto alla discussione, specialmente ai professionisti che, all'epoca, erano addestrati a decomporre i sistemi usando i primi criteri che descriveva sulla carta.
First I want to know if my assessment is correct. Does the FP paradigm and this article philosophically disagree?
No. Inoltre, ai miei occhi, la tua descrizione di come appare un programma FP non è diversa da quella che utilizza procedure o funzioni:
Data gets passed from function to function, each function being intimately aware of the data and "changing it" along the way.
... tranne per la parte "intimacy", dal momento che puoi (e spesso fai) avere funzioni che operano su dati astratti, proprio per evitare l'intimità. Quindi, hai un certo controllo su quella "intimità" e puoi regolarla come preferisci, impostando le interfacce (cioè le funzioni) per ciò che vuoi nascondere.
Quindi, non vedo alcun motivo per cui non saremmo in grado di seguire i criteri di Parnas di informazione che si nascondono usando la programmazione funzionale e finiamo con un'implementazione di un indice KWIC con simili vantaggi puntuali come sua seconda implementazione.
Assuming they agree, I'd like to know what FPs implementation of data hiding is. It's obvious to see this in OOP. You can have a private field that nobody outside the class can access. There's no obvious analogy of this to me in FP.
Per quanto riguarda i dati, è possibile elaborare astrazioni di dati e astrazioni di dati utilizzando FP. Ognuna di queste nasconde strutture e manipolazioni concrete di queste strutture in calcestruzzo utilizzando funzioni come astrazioni.
Modifica
C'è un numero crescente di asserzioni che affermano che "nascondere i dati" nel contesto di FP non è così utile (o OOP-ish (?)). Quindi, lasciatemi qui un esempio molto semplice e chiaro di SICP:
Supponiamo che il tuo sistema abbia bisogno di lavorare con numeri razionali. Un modo in cui potresti volerli rappresentare è una coppia o un elenco di due numeri interi: il numeratore e il denominatore. Così:
(define my-rat (cons 1 2)) ; here is my 1/2
Se ignori l'astrazione dei dati, molto probabilmente otterrai il numeratore e il denominatore usando car
e cdr
:
(... (car my-rat)) ; do something with the numerator
Seguendo questo approccio, tutte le parti del sistema che manipolano i numeri razionali sapranno che un numero razionale è un cons
- faranno cons
di numeri per creare razionali ed estrarli usando gli operatori di lista.
Un problema che potresti incontrare è quando devi avere una forma ridotta dei numeri razionali - le modifiche saranno richieste in tutto il sistema. Inoltre, se decidi di ridurre al momento della creazione, potresti scoprire in seguito che ridurre quando accedi a uno dei termini razionali è migliore, producendo un altro cambiamento completo.
Un altro problema è se, per ipotesi, è preferibile una rappresentazione alternativa per loro e tu decidi di abbandonare la rappresentazione cons
- di nuovo il cambiamento di fondo scala.
Qualunque sforzo sano nel gestire queste situazioni probabilmente inizierà a nascondere la rappresentazione dei razionali dietro le interfacce. Alla fine, si potrebbe finire con qualcosa di simile:
-
(make-rat <n> <d>)
restituisce il numero razionale il cui numeratore è l'intero <n>
e il cui denominatore è l'intero <d>
.
-
(numer <x>)
restituisce il numeratore del numero razionale <x>
.
-
(denom <x>)
restituisce il denominatore del numero razionale <x>
.
e il sistema non sarà più (e non dovrebbe più) sapere di cosa sono fatti i razionali. Questo perché cons
, car
e cdr
non sono intrinseci ai razionali, ma make-rat
, numer
e denom
sono . Ovviamente, questo potrebbe facilmente essere un sistema FP. Quindi, "nascondere i dati" (in questo caso, meglio conosciuto come astrazione dei dati, o lo sforzo di incapsulare rappresentazioni e strutture concrete) si presenta come un concetto pertinente e una tecnica ampiamente utilizzata ed esplorata, sia nel contesto di OO, programmazione funzionale o qualunque sia.
E il punto è ... anche se si può cercare di fare distinzioni tra il "tipo di nascondimento" o l'incapsulazione che stanno facendo (se nascondono una decisione progettuale, o strutture dati o algoritmi - nel caso di procedurale astrazioni), tutti hanno lo stesso tema: sono motivati da uno o più punti Parnas resi espliciti. Cioè:
- Changeability: se le modifiche richieste possono essere apportate localmente o diffuse attraverso il sistema.
- Sviluppo indipendente: in che misura due parti del sistema possono essere sviluppate in parallelo.
- Comprensibilità: quanta parte del sistema deve essere nota per comprendere una delle sue parti.
L'esempio sopra è stato preso dal libro SICP quindi, per la discussione completa e la presentazione di questi concetti nel libro, consiglio vivamente di dare un'occhiata a capitolo 2 . Raccomando anche di familiarizzare con i tipi di dati astratti nel contesto di FP, che porta altri problemi al tavolo.