簡體   English   中英

在scala中定義Haskell FixF

[英]Defining Haskell FixF in scala

因此,comonad.com有一系列有趣的文章與應用程序一起工作,我一直在努力將我能用到scala(為了好玩和學習)。 所以,haskell定義了FixF -

newtype FixF f a = FixF (f (FixF f) a)

它寫道,“ FixF是善良的((* -> *) -> * -> *) -> * -> *) 。它需要一個”二階Functor“的固定點(一個Functor發送一個Functor)到另一個Functor,即hask的functor類別的endofunctor,以恢復標准的“第一順序Functor”。“

kinds classify types
*                   type  A
* -> *              type F[_]
* -> * -> *         type F[_,_]
((* -> *) -> *)     type F[F'[_]]
((* -> *) ->* -> *) type F[F'[_], A] 

現在我已經看到了這一點

case class Fix[F[_]](out: F[Fix[F]])
// ((* -> *) -> * )

和這個

case class BFixF[F[_,_], A](out: F[A, BFixF[F,A]])

所以它不是第一個Fix(錯誤種類)它是第二個嗎? 我不認為種類是對的

BFixF :: ((* -> * -> * ) -> * -> *) ?

是嗎 -

    // edit as of this morning it is really not this
    class FixF[F[_[_], _], A] :: ((* -> *) -> * -> *) -> *)

是嗎 ?

    case class FixF'[F[_], A](run: F[Fix[F, A]]) 

如果是這樣,我很樂意看到正確的定義和函子

 case class FixF[F[_], A] (out: F[Fix[F, A]])

 trait FixFFunctor[F[_]: Functor] extends Functor[({type l[x] = FixF[F, x]})#l] {

   def map[A, B](f: A => B): FixF[F, A] => FixF[F, B] = ???

 }

現在紅利問題,有人能定義應用嗎?

這是一個非常酷的問題 - 我也會閱讀這些帖子,並且想知道Scala實現看起來有多可怕,但我從未嘗試過。 所以我會稍微回復一下,但請注意以下內容非常不合適(畢竟是星期六早上),並不一定代表Scala中最干凈的方式。

最好從系列第一篇文章中定義一些類型開始:

import scala.language.higherKinds
import scalaz._, Scalaz._

case class Const[M, A](mo: M)

sealed trait Sum[F[_], G[_], A]

object Sum {
  def inL[F[_], G[_], A](l: F[A]): Sum[F, G, A] = InL(l)
  def inR[F[_], G[_], A](r: G[A]): Sum[F, G, A] = InR(r)
}

case class InL[F[_], G[_], A](l: F[A]) extends Sum[F, G, A]
case class InR[F[_], G[_], A](r: G[A]) extends Sum[F, G, A]

還有一些來自博客文章的帖子

case class Embed[F[_], A](out: A)

case class ProductF[F[_[_], _], G[_[_], _], B[_], A](f: F[B, A], g: G[B, A])

如果你已經完成了上述工作,你應該對FixF應該是什么樣子FixF了解:

case class FixF[F[f[_], _], A](out: F[({ type L[x] = FixF[F, x] })#L, A])

事實證明,這有點過於嚴格,所以我們將使用以下內容:

class FixF[F[f[_], _], A](v: => F[({ type L[x] = FixF[F, x] })#L, A]) {
  lazy val out = v
  override def toString = s"FixF($out)"
}

現在假設我們想要將列表實現為“多項式函子的二階修正點”,如博客文章中所述。 我們可以從定義一些有用的別名開始:

type UnitConst[x] = Const[Unit, x]
type UnitConstOr[F[_], x] = Sum[UnitConst, F, x]
type EmbedXUnitConstOr[F[_], x] = ProductF[Embed, UnitConstOr, F, x]

type MyList[x] = FixF[EmbedXUnitConstOr, x]

現在我們可以從帖子中定義示例的Scala版本:

val foo: MyList[String] = new FixF[EmbedXUnitConstOr, String](
  ProductF[Embed, UnitConstOr, MyList, String](
    Embed("foo"),
    Sum.inL[UnitConst, MyList, String](Const())
  )
)

val baz: MyList[String] = new FixF[EmbedXUnitConstOr, String](
  ProductF[Embed, UnitConstOr, MyList, String](
    Embed("baz"),
    Sum.inL[UnitConst, MyList, String](Const())
  )
)

val bar: MyList[String] = new FixF[EmbedXUnitConstOr, String](
  ProductF[Embed, UnitConstOr, MyList, String](
    Embed("bar"),
    Sum.inR[UnitConst, MyList, String](baz)
  )
)

這看起來像我們在Haskell實現時所期望的:

scala> println(foo)
FixF(ProductF(Embed(foo),InL(Const(()))))

scala> println(bar)
FixF(ProductF(Embed(bar),InR(FixF(ProductF(Embed(baz),InL(Const(())))))))

現在我們需要我們的類型類實例。 其中大部分非常簡單:

implicit def applicativeConst[M: Monoid]: Applicative[
  ({ type L[x] = Const[M, x] })#L
] = new Applicative[({ type L[x] = Const[M, x] })#L] {
  def point[A](a: => A): Const[M, A] = Const(mzero[M])
  def ap[A, B](fa: => Const[M, A])(f: => Const[M, A => B]): Const[M, B] =
    Const(f.mo |+| fa.mo) 
}

implicit def applicativeEmbed[F[_]]: Applicative[
  ({ type L[x] = Embed[F, x] })#L
] = new Applicative[({ type L[x] = Embed[F, x] })#L] {
  def point[A](a: => A): Embed[F, A] = Embed(a)
  def ap[A, B](fa: => Embed[F, A])(f: => Embed[F, A => B]): Embed[F, B] =
    Embed(f.out(fa.out))
}

implicit def applicativeProductF[F[_[_], _], G[_[_], _], B[_]](implicit
  fba: Applicative[({ type L[x] = F[B, x] })#L],
  gba: Applicative[({ type L[x] = G[B, x] })#L]
): Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] =
  new Applicative[({ type L[x] = ProductF[F, G, B, x] })#L] {
    def point[A](a: => A): ProductF[F, G, B, A] =
      ProductF(fba.point(a), gba.point(a))
    def ap[A, C](fa: => ProductF[F, G, B, A])(
      f: => ProductF[F, G, B, A => C]
    ): ProductF[F, G, B, C] = ProductF(fba.ap(fa.f)(f.f), gba.ap(fa.g)(f.g))
  }

包括FixF本身的應用實例:

implicit def applicativeFixF[F[_[_], _]](implicit
  ffa: Applicative[({ type L[x] = F[({ type M[y] = FixF[F, y] })#M, x] })#L]
): Applicative[({ type L[x] = FixF[F, x] })#L] =
  new Applicative[({ type L[x] = FixF[F, x] })#L] {
    def point[A](a: => A): FixF[F, A] = new FixF(ffa.pure(a))
    def ap[A, B](fa: => FixF[F, A])(f: => FixF[F, A => B]): FixF[F, B] =
      new FixF(ffa.ap(fa.out)(f.out))
  }

我們還將定義終端轉換:

implicit def terminal[F[_], M: Monoid]: F ~> ({ type L[x] = Const[M, x] })#L =
  new (F ~> ({ type L[x] = Const[M, x] })#L) {
    def apply[A](fa: F[A]): Const[M, A] = Const(mzero[M])
  }

但現在我們遇到了麻煩。 我們真的需要一些額外的懶惰,所以我們會作弊:

def applicativeSum[F[_], G[_]](
  fa: Applicative[F],
  ga: => Applicative[G],
  nt: G ~> F
): Applicative[({ type L[x] = Sum[F, G, x] })#L] =
  new Applicative[({ type L[x] = Sum[F, G, x] })#L] {
    def point[A](a: => A): Sum[F, G, A] = InR(ga.point(a))
    def ap[A, B](x: => Sum[F, G, A])(f: => Sum[F, G, A => B]): Sum[F, G, B] =
      (x, f) match {
        case (InL(v), InL(f)) => InL(fa.ap(v)(f))
        case (InR(v), InR(f)) => InR(ga.ap(v)(f))
        case (InR(v), InL(f)) => InL(fa.ap(nt(v))(f))
        case (InL(v), InR(f)) => InL(fa.ap(v)(nt(f)))
      }
  }

implicit def myListApplicative: Applicative[MyList] =
  applicativeFixF[EmbedXUnitConstOr](
    applicativeProductF[Embed, UnitConstOr, MyList](
      applicativeEmbed[MyList],
      applicativeSum[UnitConst, MyList](
        applicativeConst[Unit],
        myListApplicative,
        terminal[MyList, Unit]
      )
    )
  )

也許有一種方法可以讓Scalaz 7的應用程序編碼在沒有黑客的情況下使用,但是如果有的話我不想花費我的星期六下午搞清楚。

這很糟糕,但至少現在我們可以檢查我們的工作:

scala> println((foo |@| bar)(_ ++ _))
FixF(ProductF(Embed(foobar),InL(Const(()))))

這正是我們想要的。

只需查看Haskell數據類型,我就會嘗試以下類:

import scala.language.higherKinds

class FixF[F[_,_],A](val ffix: F[FixF[F,_],A]) extends AnyVal;

當我更多地了解FixF時,我會嘗試擴展答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM