我想使用Scala cats庫和以下tutorial doc來定義一個簡單的算術表達式求值程序。在Scala貓中遞歸算術表達式的自由單子組
目標是以模塊化的方式定義DSL,可以單獨定義整數值和附加值。
我有以下代碼:
package examples
import cats._
import cats.data._
import cats.free._
import cats.free.Free._
import scala.language.higherKinds
object FreeExpr {
sealed trait ValueF[A]
case class IntValue(n: Int) extends ValueF[Int]
class Value[F[_]](implicit I: Inject[ValueF, F]) {
def intVal(n:Int): Free[F,Int] = inject[ValueF,F](IntValue(n))
}
object Value {
implicit def value[F[_]](implicit I: Inject[ValueF,F]): Value[F] = new Value[F]
}
sealed trait ArithF[A]
case class Add[A](x: A, y: A) extends ArithF[A]
class Arith[F[_]](implicit I: Inject[ArithF, F]) {
def add[A](x: A, y: A) : Free[F,A] =
Free.inject[ArithF,F](Add(x,y))
}
object Arith {
implicit def arith[F[_]](implicit I: Inject[ArithF,F]): Arith[F] = new Arith[F]
}
type Expr[A] = Coproduct[ArithF, ValueF, A]
type Result[A] = Id[A]
object ArithId extends (ArithF ~> Result) {
def apply[A](fa: ArithF[A]) = fa match {
case Add(x,y) => ??? // for { m <- x; n <- y } yield (m + n)
}
}
object ValueId extends (ValueF ~> Result) {
def apply[A](fa: ValueF[A]) = fa match {
case IntValue(n) => Monad[Id].pure(n)
}
}
val interpreter: Expr ~> Result = ArithId or ValueId
def expr1(implicit value : Value[Expr],
arith : Arith[Expr]): Free[Expr, Int] = {
import value._, arith._
for {
n <- intVal(2)
m <- add(n, n)
} yield m
}
lazy val run1 = expr1.foldMap(interpreter)
}
前面的代碼編譯,因爲我評論的「應用」爲添加的情況下的定義。我最初以爲的解決方案是被註釋掉的代碼,但是編譯器回報:
[error] ...FreeExpr.scala:40: value flatMap is not a member of type parameter A
[error] case Add(x,y) => for { m <- x; n <- y } yield (m + n)
[error] ^
你知道什麼纔是我需要的代碼改變來定義一個模塊化的方式DSL和解釋?
井類型參數A應該是一個Monad爲了能夠flatmap它。 'fa:ArithF [A]'不強制執行它......我不確定這個決議,因爲我對FreeMonads不太熟悉 –