2016-04-20 58 views
24

當您的計算步驟是獨立的時候,經常提到應用函子作爲monads的替代方案。他們經常提到的優點之一是,當您想堆疊應用程序時,不需要變壓器,因爲F[G[X]]始終也是一個應用程序。 比方說,我有以下功能:如何在Scala中堆疊應用函子

def getDataOption(): Option[Data] 
def getUserFuture(): Future[User] 
def process(data: Data, user: User) 

我想有優雅的堆疊,以獲得一個Future[Option[User]]Future[Option[Data]]和地圖與process

到目前爲止,我只想到了這一點(用貓):

Applicative[Future] 
    .compose[Option] 
    .map2(
     Applicative[Future].pure(getDataOption()), 
     getUserFuture().map(Applicative[Option].pure))(process) 

,但我敢肯定,這是很不理想。有沒有更優雅和通用的方式來實現相同?

回答

3

這裏最困難的事情就是類型推斷。這是我能做的最好的

// for the Applicative[Future[Option[?]] 
    import cats.Applicative 

    implicit val fo = { 
    import cats.std.future._ 
    import cats.std.option._ 
    Applicative[Future].compose[Option] 
    } 

    // for the |@| syntax 
    import cats.syntax.cartesian._ 

    // to guide type inference 
    type FutureOption[A] = Future[Option[A]] 

    ((Future(getDataOption): FutureOption[Data]) |@| 
    getUserFuture.map(Option.apply)).map(process _) 
+0

謝謝,我猜如果可能的話,類似於Eff/Emm monad的東西會很方便去掉樣板。 – kciesielski

+0

我認爲這裏最簡單的做法可能就是抓住'OptionT',但你可能可以做'(send(getDataOption)| @ send(getUserFuture))。map(process _)。runOption.detach。運行'以得到最終的'未來[選項[A]]'與Eff(和類似的Emm)。 – Eric

+0

對。但是,我想留在應用程序。我的問題的關鍵是看到被讚美的應用性的實際應用,他們可以堆疊而不使用變壓器。 – kciesielski