我想弄清楚如何使用scalaz7 IO和monad變壓器以優雅的純功能風格編寫這段代碼,但僅僅是無法讓我的頭轉向它。IO和未來[選項] monad變壓器
試想一下,我有這個簡單的API:
def findUuid(request: Request): Option[String] = ???
def findProfile(uuid: String): Future[Option[Profile]] = redisClient.get[Profile](uuid)
使用這個API,我可以輕鬆地寫出與OptionT變壓器這樣的非純函數:
val profileT = for {
uuid <- OptionT(Future.successful(findUuid(request)))
profile <- OptionT(findProfile(uuid))
} yield profile
val profile: Future[Option[Profile]] = profileT.run
正如你已經注意到了 - 這個函數包含findProfile ()有副作用。我想在IO monad內部隔離這種效應,並在純函數外部解釋,但不知道如何將它們結合在一起。
def findProfileIO(uuid: String): IO[Future[Option[Profile]]] = IO(findProfile(uuid))
val profileT = for {
uuid <- OptionT(Future.successful(findUuid(request)))
profile <- OptionT(findProfileIO(uuid)) //??? how to put Option inside of the IO[Future[Option]]
} yield profile
val profile = profileT.run //how to run transformer and interpret IO with the unsafePerformIO()???
它可能會如何做諮詢的任何撕成小塊?
THX @盧卡 - jacobowitz 有問題 *我用我的Play的Action.async的這裏面的代碼,所以我要回報未來的[結果]。將任務轉換爲scala.Future表示任務終止。一旦終止,Play的操作就會變成同步。你知道如何將任務轉換爲未來而無需終止? *走得更遠 - 你認爲IO Monad只是延期計算嗎?如果是這樣的話,它意味着原始的findProfile:Future也是懶惰的,它的計算也在ExecutionContext中被推遲了?在這種情況下,可能沒有必要將Future包裝到IO中 - 這個功能已經是純粹的了? –
未來的問題是它不是懶惰的。它將執行您在期貨主體內定義的任何副作用,默認情況下使其成爲不純的功能。有關詳情,請參閱此處:https://www.reddit.com/r/scala/comments/3zofjl/why_is_future_totally_unusable/ 我的建議是使用隨處可用的任務,並在需要時轉換爲或來自Future。 –
謝謝您。在昨晚深入挖掘Future/Task比較,請閱讀這篇reddit文章。 –