簡體   English   中英

貓效應和IO monad

[英]Cats-effect and the IO monad

我一直在嘗試掌握IO monad一段時間,這是有道理的。 如果我沒有弄錯的話,目標是分開副作用和實際執行的描述。 如下例所示,Scala有一種獲取環境變量的方法,該變量不是引用透明的。 出現了兩個問題。

問題1:這是一個參考透明的

問題2:如何正確(基於單元/屬性)測試這個? 不可能檢查是否相等,因為它將檢查內存引用,並且無法檢查內部函數,因為如果我沒有弄錯,則無法進行函數比較。 但是,我不想在單元測試中運行實際的副作用。 此外,這是設計錯誤還是濫用IO monad?

case class EnvironmentVariableNotFoundException(message: String) extends Exception(message)

object Env {
  def get(envKey: String): IO[Try[String]] = IO.unit.flatMap((_) => IO.pure(tryGetEnv(envKey)))

  private[this] def tryGetEnv(envKey: String): Try[String] =
    Try(System.getenv(envKey))
      .flatMap(
        (x) =>
          if (x == null) Failure(EnvironmentVariableNotFoundException(s"$envKey environment variable does not exist"))
          else Success(x)
      )
}

最好使用IO來包含程序中來自不純源的值,就像示例中的System調用一樣。 這將返回一個IO[A] ,其內容為“ 我能夠通過不純的手段獲得A ”。 此后,您可以使用作用於A純/引用透明函數,通過mapflatMap等。

這導致兩個答案。 我會問,你試圖測試的是什么屬性?

看一下這段代碼,我注意到tryGetEnvflatMap是一個復雜到足以保證測試的東西。 您可以通過將此邏輯提取到純函數中來實現。 您可以(例如)重寫這個,這樣就有一個返回IO[String]的函數,然后編寫一個(測試過的)函數,將其轉換為您想要的類型。

IO完全按照你的意思行事,但這顯然不包括使代碼引用透明! 如果你想在這里測試實際的副作用,你可以考慮將System作為參數傳遞並將其模擬為測試,就像在不使用IO的程序中一樣。

總而言之,我考慮創建一個最小的函數來調用System來創建一個IO[A] (在這種情況下,一個IO[Try[String]] )。 您可以選擇通過模擬來測試這個最小函數,但前提是您認為這樣做會增加價值。 在此之外,您可以編寫帶有A函數,並通過將純值傳遞給這些函數來測試它們。 請記住, IO上的map簽名如下,這里的f是純(可測試)函數!

sealed abstract class IO[+A] {

  def map[B](f: A => B): IO[B]
             ^ f is a pure function!
               test it by passing A values and verifying the Bs

盡管如此,這種模式鼓勵您僅在程序的最邊緣創建IO值(例如,您的main功能)。 然后,可以從純函數創建程序的其余部分,這些函數對程序運行時來自IO類型的值起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM