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

在Scala中创建Writer monad

  •  0
  • ColOfAbRiX  · 技术社区  · 8 年前

    为了学习如何创建monad并学习它们的内部机制,我正在尝试实现Writer的一个版本,下面是一些文章: You Could Have Invented Monads!

    我面临的问题是,我不能使用我在一个应用程序中创建的数据结构来进行理解。

    case class Writer( x: Double, log: String = "  Beginning of log") {
      def flatMap( f: Double => Writer ): Writer = f( x ) match {
        case Writer( fx, msg ) => Writer( fx, log + "\n  " + msg )
      }
      def map( f: Double => Double ): Double = f( x )
    }
    
    def outer( x: Double ) = Writer( Math.log( x ), s"Called outer($x)" )
    def inner( x: Double ) = Writer( Math.exp( x ), s"Called inner($x)" )
    
    def example( x: Double ): Unit = {
      // This works
      val result = Writer( x ).flatMap {
        y1 => inner(y1).flatMap { y2 => outer(y2) }
      }
      println( result )
    
      // This works
      val result2 = for { y1 <- Writer(x) } yield {
        for { y2 <- inner( y1 ) } yield {
          for { y3 <- outer( y2 ) } yield y3
        }
      }
      println( result2 )
    
      // THIS DOESN'T WORK
      val result3 = for {
        y1 <- Writer(x)
        y2 <- inner( y1 )
        y3 <- outer( y2 )
      } yield y3 // Or whatever, it doesn't work
      println( result3 )
    }
    

    我的完整代码可以在这里找到: Debuggable.scala

    1. 我明白理解力是如何被削弱的,我的问题不在那里。
    2. Writer? I hardly knew her!
    3. 我试着去理解一个作家检查scalaz的例子: GitHub scalaz WriterT 但对我来说太吵了

    我的代码里少了什么 这就像scalaz实现返回一些在理解方面很好的东西,然后用一个特定的方法运行它。但我自己找不到办法

    1 回复  |  直到 8 年前
        1
  •  1
  •   Andrey Tyukin    8 年前

    下面是如何强制它编译:

    case class Writer(x: Double, log: String = "  Beginning of log") {
      def flatMap(f: Double => Writer): Writer = f(x) match {
        case Writer(fx, msg) => Writer(fx, log + "\n  " + msg)
      }
      def map(f: Double => Double): Writer = Writer(f(x), log)
    }
    
    def outer(x: Double) = Writer(Math.log(x), s"Called outer($x)")
    def inner(x: Double) = Writer(Math.exp(x), s"Called inner($x)")
    
    def example(x: Double): Unit = {
    
      val result = Writer(x).flatMap {
        y1 => inner(y1).flatMap { y2 => outer(y2) }
      }
      println(result)
    
      val result3 = for {
        y1 <- Writer(x)
        y2 <- inner(y1)
        y3 <- outer(y2)
      } yield y3
    
      println(result3)
    }
    
    example(42)
    

    Writer(42.0,  Beginning of log
      Called inner(42.0)
      Called outer(1.73927494152050099E18))
    Writer(42.0,  Beginning of log
      Called inner(42.0)
      Called outer(1.73927494152050099E18))
    

    正如在评论中已经提到的,这个整体结构不是一个单子,而是类似于“函数的幺半群中的函数组合” Double -测井的自同态。没有办法让你的第二个例子起作用(因为 Writer 不是一个 双倍 ,但是你的 map 只需要 Double => Double ),所以我把它去掉了。