2016-02-01 16 views
13

Przypuśćmy, że chcesz agregować dane z 2 zdalnych usług oraz służyć odpowiedzi tak szybko, jak tylko mogę:Monady VS aplikacyjnych funktory dla kontraktów

def loadUser: Future[User] 
def loadData: Future[Data] 

case class Payload(user: User, data: Data) 

Rozumiem, że ten wykonuje zadania asynchroniczny kolejno:

for { 
    user <- loadUser 
    data <- loadData 
} yield Payload(user,data) 

Chociaż ten wykonuje je równolegle, ponieważ zadania są wywoływane przed asynchroniczne będąc kolejno chaine d:

val userF = loadUser 
val dataF = loadData 
for { 
    user <- userF 
    data <- dataF 
} yield Payload(user,data) 

Różnica jest jednak dla mnie zbyt nieokreślona i na pierwszy rzut oka może się nie pojawić.


Applicatives rozwiązuje również zadanie

(loadUser |@| loadData) { Payload(_,_) } 

Czy ktoś może mi powiedzieć, co wolałbym używać między applicatives i monad do wykonywania obliczeń równoległych transmisji asynchronicznej? Jakie są plusy i minusy każdego podejścia?

+2

myślę, że zasadniczo jeśli potrzebujesz wyjścia z someComputationA w celu obliczenia wyjścia someComputationB używasz monady. Jeśli chcesz tylko obliczyć dwie osobne rzeczy i połączyć je, zrobi to aplikacja aplikacyjna. Chociaż nie ma w tym nic szczególnego "podobieństwa" do zastosowań, argumentowałbym, że z powodów podanych powyżej monady są z natury sekwencyjne. Tam, jeśli potrzebujesz prawdziwie równoległych obliczeń, monady prawdopodobnie nie są strukturą, której szukasz. * waves hands * – melps

+5

Moja odpowiedź [tutaj] (http://stackoverflow.com/a/19881777/334519) ma kilka istotnych dyskusji. –

+0

Standardowym idiomem do równoległego wykonywania obliczeń 'Future' jest' zip': 'for ((user, data) <- loadUser zip loadData) yield Payload (user, data)' – Kolmar

Odpowiedz

12

Odpowiadam więc na własne pytanie, ponieważ wszystkie komentarze prowadzą do przydatnych zasobów.

Travis Brown miał ładny answer:

to tylko praktyka stały rozwój używać najsłabszej abstrakcję że dostanie pracę. Zasadniczo może to pozwolić na optymalizacje, które w innym przypadku nie byłyby możliwe, ale co ważniejsze, powoduje, że kod, który piszemy, jest bardziej przydatny do wielokrotnego użytku.

Ponadto wskazuje on interesujący fakt:

To wstyd, że zarówno Haskell i Scala obecnie uczynić pracę z monad tyle wygodniejsze (składniowo, itd.) Niż praca z aplikacyjnych funktorów

Kolmar podkreślić, że jest to możliwe do spięcia 2 futures:

for ((user, data) <- loadUser zip loadData) yield Payload(user, data) 

Wygląda jednak na to, że zipping more than 2 futures nie jest tak elegancki.

Wygląda więc na to, że aplikacyjnych funktor najlepiej nadaje się do tego zadania, ale standart biblioteka Scala nie zachęca nas znacznie do korzystania z nich w porównaniu do monady i trzeba dodatkową bibliotekę jak Scalaz lub kotów