【问题标题】:`forever` Combinator with Higher Kinded Type具有更高种类的`forever`组合子
【发布时间】:2024-04-27 05:00:02
【问题描述】:

我正在尝试从Functional Programming in Scala 运行以下组合器:

trait AddlCombinators[F[_]] extends Monad[F[_]] {
  def forever[A, B](a: F[A]): F[B] = {
    lazy val t: F[B] = forever(a)
    a flatMap (_ => t)
  }
}

但它没有编译:

[error] AddlCombinators.scala:7: value flatMap is not a member of type 
      parameter F[A]
[error]     a flatMap (_ => t)
[error]       ^

我的理解是我需要使用F[_],因为它表示一种更高种类的类型。

例如,我在本书的前一章写过Monad[List]

object ListMonad extends Monad[List] {
  def unit[A](a: => A): List[A] = List(a)

  def flatMap[A,B](ma: List[A])(f: A => List[B]): List[B] =
    ma.map(x => f(x)).flatten
}

编辑添加MonadFunctor代码

trait Functor[F[_]] {
  def map[A,B](fa: F[A])(f: A => B): F[B]
}

trait Monad[F[_]] extends Functor[F] {
    def unit[A](a: => A): F[A]
    def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B]

如何解决上述编译时错误?另外,F[_] 作为AddlCombinatorsMonad 的类型是什么意思?可以用一般的“higher kinded type”吗?

【问题讨论】:

  • 我建议您包含Monad 的定义。通常最好发布自包含代码 sn-ps(尤其是考虑到并非每个人都拥有“Scala 中的函数式编程”的副本)。不仅如此,我还期望Monad被定义为trait Monad[F[_]] { ... },但这与你对trait AddlCombinators[F[_]] extends Monad[F[_]]的定义不一致
  • @RégisJean-Gilles - 谢谢你的建议。我编辑包括MonadFunctor
  • 嗯,我是对的,你对AddlCombinators的定义是错误的,应该是AddlCombinators[F[_]] extends Monad[F]。此外,Jamil 是对的,您可以通过执行 flatMap( a ) (_ => t) 而不是 a flatMap (_ => t) 来修复您的代码。虽然有些库可能会添加语法糖来允许这种表示法(特别是 scalaz,请参阅 github.com/scalaz/scalaz#syntax),其中 a flatMap (_ => t) 基本上只会转发到 flatMap( a ) (_ => t),可以这么说。

标签: scala


【解决方案1】:

a flatMap (_ => t) 是这里的罪魁祸首。

根据给出的代码,您可以使用flatMap(a)(_ => t) 来编译它。

Monad 接口不会自动将一元运算符添加到任何参数化类型,除非您使用隐式。

F[_] 是存在类型,这意味着 F 是包含其他类型的类型,相当于:trait F {type A}。每个 Monad 都是一个 Functor,只有参数化的类型可以是 Functor,这就是为什么你需要用 F[_] 参数化 Monad。换句话说,只有参数化类型才能满足 Monad/Functor 接口。由参数化类型(* -> *) -> * 参数化的类型是更高种类的类型。 F[_] 限制最少,因此可以在此处使用最通用的类​​型。通过类型投影可以使其他参数化类型看起来像 F[_]。例如,要为右偏的 Either 类型定义 Monad,您可以将 type FA = ({type l[a] = Either[L, a]})#l 用作 F[_]。有关 Monad for Either 的完整代码,请参阅 here

【讨论】: