如何定义一个递归代数用于免费应用?

时间:2018-03-27 09:49:45

标签: scala scalaz applicative scala-cats

我面临定义与FreeApplicative一起使用的递归代数的问题。

这是我失败的尝试。 让我们假设我们希望功能标记(组)有效值。 我已经插入了虚拟Print以获得一些构造函数。

sealed trait Algebra[F[_],T]
case class Print[F[_]](s: String) extends Algebra[F,String]
case class Prefix[F[_],T](p: String, tagged: F[T]) extends Algebra[F,T]

当我尝试定义免费类型FA时(使用kind-projector

type FA[T] = FreeApplicative[Algebra[FA,?],T]

然后编译器抱怨

  

错误:(28,38)涉及FA类型的非法循环引用       类型FA [T] = FreeApplicative [Alg [FA,?],T]

我该如何解决这个问题?

我认为在使用Free(monads)时,Prefix的签名可以省略对tagged的引用。 当monad链接他们的代数调用时,人们可以简单地记住执行路径上的所有前缀调用。 但是对于Applicative,我看不出如何实现这一点。

2 个答案:

答案 0 :(得分:2)

您要求Algebra的说明参考使用Algebra构建的免费程序。

您需要定义自己的“递归”免费应用程序:

case class FreeApRec[F[_[_], _], A](fa: FreeApplicative[F[FreeApRec[F, ?], ?], A])

并实现您需要的方法(这将只转发到FreeApplicative的方法并包装结果)。

Here is the same done for the Free monad.

您还可以通过更高级别的定点运算符定义上面的FreeApRec类型,但定义变得不那么透明:

case class HFix[F[_[_], _], A](unfix: F[HFix[F, ?], A])

type FreeApRecF[F[_[_], _], K[_], A] = FreeApplicative[F[K, ?], A]

type FreeApRec[F[_[_], _], A] = HFix[FreeApRecF[F, ?[_], ?], A]

答案 1 :(得分:1)

这不是一个解决方案,而是另一种方法,可以看出为什么FreeApplicative没有做你想做的事情,以及如何推导出 Tomas Mikula的回答中提到的正确签名。

FreeApplicative[F, A]的种类是

(* -> *) -> * -> *

这实际上意味着FreeApplicative采用F类型* -> *的仿函数,并再次构建另一个类似FreeApplicative[F, ?]的仿函数* -> *

但是,您的Algebra不是* -> *,而是

(* -> *) -> * -> *

并且你想要一个“事物”,比如FreeApRec从它构建一个类似* -> *的仿函数,也就是说,FreeApRec应该是

((* -> *) -> * -> *) -> * -> *

现在,这与Tomas Mikula写下的签名非常吻合:

((* -> *) -> * -> *) -> * -> *
 \      /    |          |
  \    /     |          |
   \  /      |          |
   _[_]      _          |
 \                /     |
  \              /      |
   \            /       |
    \          /        |
     F[_[_], _]         A
 \                          /
  \                        /
   \                      /
    \                    /
    FreeApRec[F[_[_],_],A]

标准FreeApplicative没有此签名。如果您调用普通函数的“默认类别”,每个人都隐含地使用C,那么FreeApplicative会将问题[C, C]映射到其他仿函数[C, C],但您想要[[C,C] x C, C][C, C]。这又是一个类别 - 理论 - 仿函数,但不是普通的fp - Functor,因为它有一个不同的类别作为域。