Scala中实现M特质时State类出现底层类型不匹配错误的原因是什么
错误核心原因
- 你在
State[A, S]类上已经定义了状态类型参数S,但实现unit和★方法时,又在方法签名上额外声明了同名泛型参数[S]。这个方法级的S会遮蔽类上定义的S,二者是完全独立的类型,自然会出现类型不匹配的报错。 - 你传入的
f的返回值是M[B],直接将其当做State[B, S]调用传入s1也是不成立的,编译器无法确定M[B]的实际类型,只能推断为Any,对应了你后面两个类型不匹配的报错。
两种修正方案
方案1:调整Monad定义为高阶类型,适配State双类型参数的特性
这是Scala中实现带状态Monad的标准写法:
// Monad定义调整为高阶类型,适配需要多参数的类型构造器 trait M[F[_]] { def unit[A](a: A): F[A] def ★[A, B](fa: F[A], f: A => F[B]): F[B] } // State定义,状态类型S在前,值类型A在后符合常规使用习惯 case class State[S, A](run: S => (A, S)) // 给指定状态类型的State实现Monad实例 given stateMonad[S]: M[[X] =>> State[S, X]] with { def unit[A](a: A): State[S, A] = State(s => (a, s)) def ★[A, B](fa: State[S, A], f: A => State[S, B]): State[S, B] = State { s0 => val (a, s1) = fa.run(s0) f(a).run(s1) } }
方案2:沿用你提到的trait State[A] extends M[A]写法
这种写法需要把状态类型S设为类型成员,保证整个State实例的状态类型统一:
trait M[A] { def unit(a: A): M[A] def ★[B](f: A => M[B]): M[B] } trait State[A] extends M[A] { // 把S定义为类型成员,避免泛型参数冲突 type S def run: S => (A, S) override def unit(a: A): State[A] = new State[A] { type S = State.this.S override def run: S => (A, S) = s => (a, s) } override def ★[B](f: A => M[B]): M[B] = new State[B] { type S = State.this.S override def run: S => (B, S) = s0 => { val (a, s1) = State.this.run(s0) val stateB = f(a).asInstanceOf[State[B] { type S = State.this.S }] stateB.run(s1) } } }
你提到的trait State[A] extends M[A]的写法完全可行,核心要避免的就是方法级泛型遮蔽外层已经定义的同名称类型,同时保证同一个State计算流中的状态类型始终一致。
内容的提问来源于stack exchange,提问作者Shodz
相关产品推荐
相关产品推荐

