You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跟随Free Monads讲座实现解释器时遭遇编译错误求助

Fixing "Expression of type Property does not conform to cats.Id" in Your Free Monad Interpreter

Hey there, let's walk through fixing this issue step by step. I looked at your code and spotted a couple of things causing the compile error and other potential issues:

1. Fix HTML Entity Symbols First

Your code uses HTML entities like &lt;-, ~&gt;, and =&gt; instead of actual Scala syntax (<-, ~>, =>). These symbols break the compiler's ability to parse code correctly, leading to misleading type errors like the one you're seeing.

Replace all those entities with proper Scala operators:

  • &lt;- → <-
  • ~&gt; → ~>
  • =&gt; → =>

For example, your updatePost for-comprehension should look like this:

def updatePost(propertyId: Int, post: String): Script[Property] = {
  for {
    property <- fetchById(propertyId)
    p1 = property.copy(post = post)
    _ <- log("Updating")
    _ <- save(p1)
  } yield p1
}

2. Add a Functor Instance for AppAction

Free.liftF (used in your lift method) requires a Functor instance for AppAction, and foldMap also depends on this. Without it, the compiler will throw additional errors. You can either implement this manually or use Cats' automatic derivation (recommended for simplicity).

Option A: Automatic Derivation (with Cats Macros)

First, ensure you have the cats-macros dependency in your build. Then add the derivation to your code:

import cats.derive._

sealed trait AppAction[A] {
  def lift: Script[A] = Free.liftF(this)
}

// Add this implicit instance
implicit val appActionFunctor: Functor[AppAction] = semiauto.functor[AppAction]

Option B: Manual Implementation

If you don't want to use macros, you can write the Functor manually (though this gets tedious as you add more actions):

implicit val appActionFunctor: Functor[AppAction] = new Functor[AppAction] {
  override def map[A, B](fa: AppAction[A])(f: A => B): AppAction[B] = fa match {
    case FetchById(id) => FetchById(id).asInstanceOf[AppAction[B]]
    case Save(p) => Save(p).asInstanceOf[AppAction[B]]
    case Log(msg) => Log(msg).asInstanceOf[AppAction[B]]
  }
}

3. Verify the Interpreter's Return Types

The Id type in Cats is just a type alias for the identity type (type Id[A] = A), so returning Property(1, "2000") directly should be valid for Id[Property]. Once you fix the symbol issues and add the Functor instance, this type error should resolve itself.

If you still see issues, you can explicitly type the return value in the match case to help the compiler:

case FetchById(_) => Property(1, "2000"): Id[Property]

Full Fixed Code

Here's the complete corrected code with all fixes applied:

package object example {
  import cats._
  import cats.data._
  import cats.free._
  import cats.implicits._
  import cats.derive._

  case class Property(Id: Int, post: String)

  type Script[A] = Free[AppAction, A]

  sealed trait AppAction[A] {
    def lift: Script[A] = Free.liftF(this)
  }

  implicit val appActionFunctor: Functor[AppAction] = semiauto.functor[AppAction]

  case class FetchById(propertyId: Int) extends AppAction[Property]
  case class Save(property: Property) extends AppAction[Unit]
  case class Log(message: String) extends AppAction[Unit]

  def fetchById(id: Int): Script[Property] = FetchById(id).lift
  def save(property: Property): Script[Unit] = Save(property).lift
  def log(message: String): Script[Unit] = Log(message).lift

  def updatePost(propertyId: Int, post: String): Script[Property] = {
    for {
      property <- fetchById(propertyId)
      p1 = property.copy(post = post)
      _ <- log("Updating")
      _ <- save(p1)
    } yield p1
  }

  object TestInterp extends (AppAction ~> Id) {
    def apply[A](fa: AppAction[A]): Id[A] = fa match {
      case FetchById(_) => Property(1, "2000")
      case Save(_) => ()
      case Log(msg) => println(msg)
    }

    def run[A](script: Script[A]) = script.foldMap(this)
  }
}

Testing the Fix

You can test it by running:

TestInterp.run(updatePost(1, "Updated post"))

This should print "Updating" and return the updated Property instance.

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:57:35