将方法从伴侣对象移动到类时类型不匹配

问题描述

我是Scala的新手,所以答案可能很明显。

在Scala FP in Scala中通过FP时,我注意到unit方法放在伴随对象上,而不是放在类上,因此我尝试将其移到类上。 它导致了我不理解的错误,有人可以向我解释吗?

在类上取消对unit方法的注释并在伴随对象上将其注释掉时,将导致此错误

type mismatch

那是为什么?

import State._

case class State[S,A](run: S => (A,S)) {
  def map[B](f: A => B): State[S,B] =
    flatMap(a => unit(f(a)))

  def map2[B,C](sb: State[S,B])(f: (A,B) => C): State[S,C] =
    flatMap(a => sb.map(b => f(a,b)))

  def flatMap[B](f: A => State[S,B]): State[S,B] = State(s => {
    val (a,s1) = run(s)
    f(a).run(s1)
  })

  // This results in an error here:
  //     flatMap(a => unit(f(a))) ... required A,found B
  // def unit(a: A): State[S,A] = State(s => (a,s)) // ERROR
}

object State {
  // Comment out when uncommenting above
  def unit[S,A](a: A): State[S,s))
}

解决方法

该错误解释了问题所在,但这是故障所在。

map开头:

def map[B](f: A => B): State[S,B] =
  flatMap(a => unit(f(a)))

由于f返回的未知类型为B,因此正在调用值为unit类型的B。但是unit被定义为采用A,它是case class的类型参数:

def unit(a: A): State[S,A] = State(s => (a,s))

由于B可能不是A,因此编译器会抱怨。


伴随对象内部的代码不同:

object State {
  def unit[T,U](a: U): State[T,U] = State(s => (a,s))
}

我已经重命名了类型参数,以明确它们现在与case类的类型参数无关。而且,由于unit的参数类型可以是任何类型的U,因此可以将B类型的值传递给它。


要在unit中固定case class的定义,请为其提供类型参数:

case class State[S,A](run: S => (A,S)) {
   // ...

   def unit[T](a: T): State[S,T] = State(s => (a,s))
}