Scala编译器不能正确推断类型

我正在阅读Scala函数式编程的第6章。 我已经接近了本章的最后一个练习(即:6.11),这使我怀疑某些代码行。

这里是练习的描述:

让我们来实现一个有限状态自动机,它可以模拟一个简单的糖果分配器。 机器有两个输入:您可以插入一个硬币,或者您可以通过旋转旋钮来分配糖果。 它可以处于两种状态之一:锁定或解锁。 它还会跟踪剩余的糖果数量以及它包含的硬币数量。

  • 如果还有糖果,将硬币插入锁定的机器将解锁。
  • 转动解锁机器上的旋钮将导致它分配一颗糖果并返回到锁定状态。
  • 转动锁定机器上的旋钮或将硬币插入未锁定机器不起作用。
  • 没有糖果的机器会忽略任何输入。
  • 方法simulateMachine应根据输入列表操作机器并返回机器中残留的硬币和糖果的数量。 例如,如果输入机器有10个硬币和5个糖果,并且总共购买了4个糖果,则输出应该是(14,1)。

    以下是我自己实施的可测试单元。

    object Test extends App {
    
      class Comparison(value: Int) {
        def shouldBe(other: Int): Boolean = value == other
      }
    
      implicit def enrichIntegers(value: Int) = new Comparison(value)
    
      val machine = Machine(locked  = true, candies = 5, coins = 10)
      val input = List(Coin, Turn, Coin, Turn, Coin, Turn, Coin, Turn)
      val result = StateChange.simulateMachine(input)
      val tuple: ((Int, Int), Machine) = result.run(machine)
      val ((coins, candies), _) = tuple
    
      (coins shouldBe 14) && (candies shouldBe 1) match {
        case true => println("Ok")
        case false => println("Ko")
      }
    }
    
    sealed trait Input
    case object Coin extends Input
    case object Turn extends Input
    case class Machine(locked: Boolean, candies: Int, coins: Int)
    
    case class State[S,+A](run: S => (A, S)) {
      def map[B](f: A => B): State[S, B] = State(
        s => {
          val (a, newState) = this.run(s)
          (f(a), newState)
        }
      )
      def map2[B,C](sb: State[S, B])(f: (A, B) => C): State[S, C] = State(
        s => {
          val (a, newState) = this.run(s)
          val (b, finalState) = sb.run(newState)
          (f(a, b), finalState)
        }
      )
    
      def flatMap[B](f: A => State[S, B]): State[S, B] = State(
        s => {
          val (a, state): (A, S) = this.run(s)
          f(a).run(state)
        }
      )
    }
    
    object State {
    
      def get[S]: State[S, S] = State(s => (s, s))
      def set[S](s: S): State[S, Unit] = State(_ => ((), s))
    
      def modify[S](f: S => S): State[S, Unit] = {
        for {
          s <- get
          _ <- set(f(s))
        } yield ()
      }
    
      def unit[S, A](a: A): State[S, A] = State(s => (a,s))
    
      def sequence[S, A](fs: List[State[S,A]]): State[S, List[A]] = {
        fs.foldRight[State[S, List[A]]](State.unit(Nil))((elem, acc) => elem.map2(acc)((a,b)=>a::b))
      }
    }
    
    object StateChange {
      def update(i: Input)(s: Machine) = {
        (i,s) match {
          case (_, Machine(_,0,_)) => s
          case (Coin, Machine(false,_,_)) => s
          case (Turn, Machine(true,_,_)) => s
          case (Coin, Machine(true,candies,coins)) => Machine(false,candies,coins+1)
          case (Turn, Machine(false,candies,coins)) => Machine(true,candies-1,coins)
        }
      }
    
      def simulateMachine(inputs: List[Input]): State[Machine, (Int, Int)] = {
        import State._
        val list: State[Machine, List[Unit]] = sequence(inputs.map(input => modify(update(input))))
        list.flatMap((_: List[Unit]) =>
           State(
             s => {
               val currentState: State[Machine, Machine] = get   // <= my doubt is here
               val (currentMachine, newState) = currentState.run(s)
               ((currentMachine.coins, currentMachine.candies), newState)
             }
           )
         )
      }
    }
    

    我的疑问是关于simulateMachine定义中的以下行:

    val getState: State[Machine, Machine] = get
    

    simulateMachine实现了一个desugared版本,我写的是为了更好地理解原来为解释练习而写的理解内容。

    我的问题是:

    为什么我需要显式指定currentState的类型来编译代码? 事实上,如果没有这个State[Machine, Machine]类型定义,上面的代码片段不能编译。

    为什么编译器无法推断出实际的类型? 这只是一个类型推断限制的问题,还是我在这里错过了一些东西?

    希望我的问题很清楚,谢谢!


    如果你不提供类型参数来get并且不明确指定currentState的类型,Scala就无法知道类型。 它必须从((currentMachine.coins, currentMachine.candies), newState)val (currentMachine, newState) = currentState.run(s)向后推断类型((currentMachine.coins, currentMachine.candies), newState)但是Scala的类型推断功能不够强大。

    链接地址: http://www.djcxy.com/p/66213.html

    上一篇: Scala compiler does not infer type properly

    下一篇: Scala type inference and multiple arguments list