示例简单IO类型如何消除“中的副作用”;Scala中的FP“吗?”;?

示例简单IO类型如何消除“中的副作用”;Scala中的FP“吗?”;?,scala,for-comprehension,io-monad,Scala,For Comprehension,Io Monad,我正在阅读第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 R

我正在阅读第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 ()
对象IO扩展Monad[IO]{
def单元[A](A:=>A):IO[A]=新IO[A]{def run=A}
def平面图[A,B](fa:IO[A])(f:A=>IO[B])=fa平面图f
def应用[A](A:=>A):IO[A]=单位(A)
}
def ReadLine:IO[String]=IO{ReadLine}
def PrintLine(msg:String):IO[Unit]=IO{println(msg)}
def转换器:IO[单位]=用于{

_将
IO
monad视为程序定义的一小部分的最简单方法

因此:

  • 这是
    IO
    定义,
    run
    方法定义了
    IO
    monad的功能。
    newio[A]{def run=A}
    是创建类实例和定义方法
    run
    的一种方式
  • 有一点语法上的甜头在起作用。
    IO{readLine}
    IO.apply{readLine}
    IO.apply(readLine)相同
    其中
    readLine
    是类型为
    =>String
    的按名称调用函数。这从
    对象IO
    调用
    单元
    方法,因此这只是创建尚未运行的
    IO
    类的实例
  • 由于
    IO
    是一个monad,因此可以使用for construction。它需要以类似
    result的语法存储每个monad操作的结果
    
  • 您的
    IO
    的定义如下:

    trait IO { def run: Unit }
    
    根据这个定义,您可以理解编写
    newio[A]{def run=A}
    意味着从trait初始化一个匿名类,并将
    A
    指定为调用
    IO.run
    时运行的方法。因为
    A
    是A,所以在创建时实际上不会运行任何操作

  • Scala中遵循
    apply
    方法约定的任何对象或类都可以称为:
    ClassName(args)
    ,编译器将在对象/类上搜索
    apply
    方法,并将其转换为
    ClassName.apply(args)
    call。一个更详细的回答。同样,因为
    IO
    伴生对象拥有这样一种方法:

    def apply[A](a: => A): IO[A] = unit(a)    
    
    扩展是允许的。因此我们实际上调用
    IO.apply(readLine)

  • \uu
    。此事件表示“我不关心从
    打印行
    返回的值,放弃它”。之所以如此,是因为返回的值是的,而我们与此无关

  • 并不是说
    IO
    数据类型删除了执行IO的部分,而是它将其推迟到以后的某个时间点。我们通常说IO在“边缘”运行在应用程序的
    Main
    方法中,这些与外部世界的交互仍然会发生,但由于我们将它们封装在IO中,我们可以在程序中将它们作为值进行推理,这带来了很多好处。例如,我们现在可以合成副作用,并取决于它们执行的成功/失败我们可以模拟这些IO效果(),以及许多其他令人惊讶的好特性


  • 您好@Yuval非常感谢!顺便说一句,我可以知道IO中的
    a
    将分配给哪个函数吗?我们将如何调用
    IO。运行
    ?@injoy
    a
    将是您提供的任何函数。例如,您的表达式之一是
    IO{readLine}
    ,其中我们将读取行函数指定为
    a
    。对不起,我的意思是“理解”中的三行都返回IO类型。它们不是真的将行打印到标准输出,对吗?那么我们如何才能真正打印这些行呢?谢谢。@injoy,在您取回
    IO[Unit]之后
    值从
    转换器
    方法,您需要调用
    运行
    转换器。运行
    。再次注意,运行IO应该发生在程序的边缘。嗨@Yuval,理解如何返回IO[单位]值?我想
    _