【问题标题】:How to implement Applicative for State[S, A] in scala / cats如何在 scala/cats 中为 State[S, A] 实现 Applicative
【发布时间】:2021-05-06 23:10:32
【问题描述】:

this session SystemFw 中给出了一个使用 vanilla scala 实现 State[S, A] 的示例,当按照示例进行操作时,我在为 vanilla State 类型提供应用程序定义时遇到了麻烦(为了获得 commands.traverse 工作.见代码here

我试图做一个隐式def来解决Applicative实例,但没有弄清楚如何处理2类型参数。

该类型如何实现Applicative:

 case class State[S, A](modify: S => (A, S)) {

  def runA(initial: S): A = modify(initial)._1

  def flatMap[B](f: A => State[S, B]): State[S, B] =
    State { s =>
      val (result, nextState) = modify(s)
      f(result).modify(nextState)
    }
  }

错误代码:

  implicit def stateApplicative[S, A]: Applicative[State[S, A]] = new Applicative[State[S, A]] {
    override def pure[A](x: A): State[A???] = ???   // error

    override def ap[A, B](ff: State[A => B])(fa: State[A???]): State[B] = ???   // error
  }

【问题讨论】:

    标签: scala


    【解决方案1】:

    基本上,解决这个问题的方法总是固定一个类型参数。

    State 的情况下,您希望更改状态中的值,但不更改状态本身的类型,因此您修复 S
    因此,您可以为给定的特定状态创建应用程序,例如 Int

    type IntState[A] = State[A, Int]
    
    implicit final val intStateApplicative: Applicative[IntState] =
      new Applicative[IntState] {
        // Some implementation.
      }
    

    但是,在完成实现之后,您会发现知道SInt 的事实毫无意义。如果SString 或其他什么,我们可以复制并粘贴整个代码。
    所以,我们想要的是一种方式来说明这适用于任何S,我们可以使用类型 lambda(即类型级别的函数)来做到这一点。

    type StateTypeFun[S] = { type F[A] = State[A, S] }
    
    implicit final def stateApplicative[S]: Applicative[StateTypeFun[S]#F] =
      new Applicative[StateTypeFun[S]#F] {
        // Some implementation.
      }
    

    这就是我们解决这个问题的方法。
    请注意,类型别名不是必需的,但会使代码更易于阅读,但您可以使用Applicative[({ type F[A] = State[A, S]})#F]


    顺便说一句,因为创建类型 lambdas 的必要性在 Scala 2 中有些常见,所以我们有 kind projector,而 Scala 3 有合适的 syntax support

    【讨论】:

      猜你喜欢
      • 2019-05-19
      • 2015-07-11
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 2017-05-08
      • 1970-01-01
      • 1970-01-01
      • 2019-09-23
      相关资源
      最近更新 更多