Qual è il metodo di programmazione funzionale per combinare due "flussi" di dati?

3

Sto cercando di capire quale sia il modo appropriato per affrontare questo problema in modo funzionale. Presumo che ci sia una struttura dati o una tecnica funzionale che renderà questo facile da gestire.

Il problema è che sto facendo una chiamata API per ottenere due bit di dati, ne uso uno in un'altra chiamata API e se la chiamata funziona, allora uso l'altro bit di dati in una seconda chiamata API. Sto avendo difficoltà a far scorrere tutto insieme. Naturalmente le chiamate API possono fallire, quindi restituiscono Either e mi piacerebbe che fosse tutta una lunga catena, ma non riesco a capire come farlo.

In una lingua imperativa lo farei:

let response = apiCall1();
// error handling, return failure

// do some processing on the response
let json = getJsonBody(response);
let bit1 = json['bit1'];
let bit2 = json['bit2'];

let response2 = apiCall2(bit1);
// error handling, return failure

let response3 = apiCall3(bit2);
// error handling, return failure

return response3 // return success

Se il risultato di ogni chiamata API era l'input della funzione successiva, avrei fatto qualcosa del genere:

return apiCall1()
   .map(jsonBody)
   .map(apiCall2)
   .map(jsonBody)
   .map(apiCall3)

Quindi qual è il modo funzionale per ottenere questo risultato?

apiCall1 ----
   |         |
   |         |
   v         |
apiCall2     |
   |         |
   |         |
   v         |
apiCall3 <---|
    
posta Gregory Bell 30.07.2016 - 00:44
fonte

1 risposta

7

Questo è dove le proprietà monadiche di Eithers sono utili (anche se non devi capire le monadi per trarne vantaggio). La maggior parte dei linguaggi di programmazione funzionale ha un modo per scrivere facilmente questo tipo di concatenamento. In Haskell è notazione . In Scala è per la comprensione . Dato che sono più familiare con Scala, lo dimostrerò di seguito.

val response = for {
  response  <- apiCall1().right
  json = getJsonBody(response)
  response2 <- apiCall2(json("bit1")).right
  response3 <- apiCall3(json("bit2")).right
} yield response3

Qui, usi la proiezione destra di ciascuno dei Eithers . Esegue fondamentalmente un flatMap sui valori Right dei risultati delle chiamate api. Non appena viene raggiunto un Left , tuttavia, interrompe il resto delle chiamate e restituisce Left come risultato finale.

Si noti che questo è solo zucchero sintattico. Il compilatore lo traduce in una serie di flatMaps , e puoi scriverlo in questo modo se preferisci, ma in questo modo è molto più facile da leggere.

    
risposta data 30.07.2016 - 01:43
fonte

Leggi altre domande sui tag