代码之家  ›  专栏  ›  技术社区  ›  injoy

示例简单IO类型如何消除“scala中的fp”中的副作用?

  •  3
  • injoy  · 技术社区  · 6 年前

    我正在阅读第13.2.1章,并遇到了一个可以同时处理IO输入和消除副作用的示例:

    object IO extends Monad[IO] {
      def unit[A](a: => A): IO[A] = new IO[A] { def run = a }
      def flatMap[A,B](fa: IO[A])(f: A => IO[B]) = fa flatMap f
      def apply[A](a: => A): IO[A] = unit(a)    
    }
    
    def ReadLine: IO[String] = IO { readLine }
    def PrintLine(msg: String): IO[Unit] = IO { println(msg) }
    
    def converter: IO[Unit] = for {
      _ <- PrintLine("Enter a temperature in degrees Fahrenheit: ")
      d <- ReadLine.map(_.toDouble)
      _ <- PrintLine(fahrenheitToCelsius(d).toString)
    } yield ()
    

    关于这段代码,我有几个问题:

    1. unit 功能,什么功能 def run = a 真的吗?
    2. ReadLine 功能,什么功能 IO { readLine } 真的吗?它真的会执行 println 函数还是只返回IO类型?
    3. 什么? _ 为了理解意味着( _ <- PrintLine("Enter a temperature in degrees Fahrenheit: ") )?
    4. 为什么它能消除IO副作用?我看到这些函数仍然与输入和输出交互。
    2 回复  |  直到 6 年前
        1
  •  4
  •   Yuval Itzchakov    6 年前
    1. 你的定义 IO 如下:

      trait IO { def run: Unit }
      

      按照这个定义,你可以理解 new IO[A] { def run = a } 意味着根据特性初始化一个匿名类,并分配 a 当你调用 IO.run . 因为 是一个 by name parameter ,创建时实际上没有运行任何内容。

    2. scala中遵循 apply 方法,可以调用为: ClassName(args) ,编译器将在其中搜索 应用 方法,并将其转换为 ClassName.apply(args) 打电话。更详尽的答案 can be found here . 因此,因为 输入输出 伴生对象具有这样的方法:

      def apply[A](a: => A): IO[A] = unit(a)    
      

      允许膨胀。因此我们实际上 IO.apply(readLine) 相反。

    3. _ has many overloaded uses in Scala . 此事件表示“我不关心返回的值” PrintLine 扔掉它。因为返回的值是 type Unit 这与我们无关。

    4. 不是那样的 输入输出 数据类型 移除 做IO的一部分,就是它 推迟 到了稍后的时间点。我们通常说IO运行在应用程序的“边缘”,在 Main 方法。这些与外部世界的交互仍然会发生,但是由于我们将它们封装在IO中,我们可以对它们进行推理。 作为价值 在我们的项目中,这带来了很多好处。例如,我们现在可以 组成 副作用,取决于执行的成功/失败。我们可以模拟这些IO效果( using other data types such as Const 以及许多其他令人惊讶的好特性。

        2
  •  2
  •   Ivan Stanislavciuc    6 年前

    最简单的方法 IO monad作为程序定义的一小部分。

    因此:

    1. 这是 输入输出 定义, run 方法定义了什么 输入输出 单子确实如此。 new IO[A] { def run = a } scala是创建类实例和定义方法的方法吗? 运行 .
    2. 有一点语法上的糖分正在发生。 IO { readLine } 一样 IO.apply { readLine } IO.apply(readLine) 哪里 readLine 是按名称调用类型的函数 => String . 这叫 unit 方法从 object IO 因此,这只是 输入输出 尚未运行的类。
    3. 自从 输入输出 是单子,可以用来理解。它要求以如下语法存储每个monad操作的结果 result <- someMonad . 要忽略结果, _ 可以使用,因此 _ <- someMonad 读取为执行monad,但忽略结果。
    4. 这些方法都是 输入输出 定义,它们不运行任何东西,因此没有副作用。副作用只出现在 IO.run 被称为。
    推荐文章