加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

一步一步/深层解释:(Co)Yoneda(优选在scala)通过协同的力量

发布时间:2020-12-16 09:48:40 所属栏目:安全 来源:网络整理
导读:一些背景代码 /** FunctorStr: ∑ F[-]. (∏ A B. (A - B) - F[A] - F[B]) */trait FunctorStr[F[_]] { self = def map[A,B](f: A = B): F[A] = F[B]}trait Yoneda[F[_],A] { yo = def apply[B](f: A = B): F[B] def run: F[A] = yo(x = x) def map[B](f: A
一些背景代码

/** FunctorStr: ∑ F[-]. (∏ A B. (A -> B) -> F[A] -> F[B]) */
trait FunctorStr[F[_]] { self =>
  def map[A,B](f: A => B): F[A] => F[B]
}

trait Yoneda[F[_],A] { yo =>

  def apply[B](f: A => B): F[B]

  def run: F[A] =
    yo(x => x)

  def map[B](f: A => B): Yoneda[F,B] = new Yoneda[F,B] {
    def apply[X](g: B => X) = yo(f andThen g)
 }
}

object Yoneda {

  implicit def yonedafunctor[F[_]]: FunctorStr[({ type l[x] = Yoneda[F,x] })#l] =
    new FunctorStr[({ type l[x] = Yoneda[F,x] })#l] {
      def map[A,B](f: A => B): Yoneda[F,A] => Yoneda[F,B] =
        _ map f
    }

  def apply[F[_]: FunctorStr,X](x: F[X]): Yoneda[F,X] = new Yoneda[F,X] {
    def apply[Y](f: X => Y) = Functor[F].map(f) apply x
  }
} 



trait Coyoneda[F[_],A] { co =>

  type I

  def fi: F[I]

  def k: I => A

  final def map[B](f: A => B): Coyoneda.Aux[F,B,I] =
    Coyoneda(fi)(f compose k)

}

object Coyoneda {

  type Aux[F[_],A,B] = Coyoneda[F,A] { type I = B }

  def apply[F[_],A](x: F[B])(f: B => A): Aux[F,B] =
    new Coyoneda[F,A] {
     type I = B
     val fi = x
     val k = f
   }

  implicit def coyonedaFunctor[F[_]]: FunctorStr[({ type l[x] = Coyoneda[F,x] })#l] =
   new CoyonedaFunctor[F] {}

  trait CoyonedaFunctor[F[_]] extends FunctorStr[({type l[x] = Coyoneda[F,x]})#l] {
   override def map[A,B](f: A => B): Coyoneda[F,A] => Coyoneda[F,B] =
     x => apply(x.fi)(f compose x.k)
 }

  def liftCoyoneda[T[_],A](x: T[A]): Coyoneda[T,A] =
   apply(x)(a => a)

 }

现在我以为我理解yoneda和coyoneda有点只是从类型 –
?即:
?他们量化/抽象在一些类型构造函数中固定的映射
??F和某种类型a,到任何类型B返回F [B]或(Co)Yoneda [F,B]。
因此,提供免费的地图融合(?这是类似地图的剪切规则吗?)。
但我看到Coyoneda是任何类型构造函数F的函子,无论F是Functor,
?并且我没有完全掌握。
现在我在一个情况,我试图定义一个Coroutine类型,
?(我正在看https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/coroutines-for-streaming/part-2-coroutines的类型,开始使用)

case class Coroutine[S[_],M[_],R](resume: M[CoroutineState[S,M,R]])

sealed trait CoroutineState[S[_],R]

  object CoroutineState {
    case class Run[S[_],R](x: S[Coroutine[S,R]]) extends CoroutineState[S,R]
    case class Done[R](x: R) extends CoroutineState[Nothing,Nothing,R]

   class CoroutineStateFunctor[S[_],M[_]](F: FunctorStr[S]) extends 
      FunctorStr[({ type l[x] = CoroutineState[S,x]})#l] {
        override def map[A,B](f : A => B) : CoroutineState[S,A] => CoroutineState[S,B]
        =
        { ??? }
    }
  }

我认为如果我更好地理解Coyoneda,我可以利用它来做S& M类型构造函数方法容易,加上我看到Coyoneda可能在定义递归方案中发挥作用
?因为函子的要求是普遍的。

所以我怎么能使用coyoneda来使类型构造函数像例如协同状态?
或类似暂停函子?

解决方法

Yoneda的秘密是它“稍稍”推迟Functor实例的需要。这是棘手的第一,因为我们可以定义实例Functor(Yoenda f),而不使用f的Functor实例。

newtype Yoneda f a = Yoneda { runYoneda :: forall b . (a -> b) -> f b }

instance Functor (Yoneda f) where
  fmap f y = Yoneda (ab -> runYoneda y (ab . f))

但是关于Yoneda的聪明的部分是它应该是同构的,但是这个同构的见证要求f是一个Functor:

toYoneda :: Functor f => f a -> Yoneda f a
toYoneda fa = Yoneda (f -> fmap f fa)

fromYoneda :: Yoneda f a -> f a
fromYoneda y = runYoneda y id

因此,在Yoneda的Functor实例的定义期间,不是对Functor实例呼吁f,它对Yoneda本身的构造获得“deferred”。在计算上,它还具有将所有fmaps变成具有“延续”函数(a→b)的组合的好的属性。

相反发生在CoYoneda。例如,无论f是否,CoYoneda f仍然是一个Functor

data CoYoneda f a = forall b . CoYoneda (b -> a) (f b)

instance Functor (CoYoneda f) where
  fmap f (CoYoneda mp fb) = CoYoneda (f . mp) fb

然而现在当我们构造同构的见证时,Functor实例被要求在另一边,当降低CoYoenda f a到f a:

toCoYoneda :: f a -> CoYoneda f a
toCoYoneda fa = CoYoneda id fa

fromCoYoneda :: Functor f => CoYoneda f a -> f a
fromCoYoneda (CoYoneda mp fb) = fmap mp fb

我们再次注意到fmap的属性,只是组成沿着最终的延续。

所以这两种都是一种“忽略”Functor需求一段时间,特别是在执行fmaps时。

现在让我们谈谈这个我认为有一个Haskell类型的Coroutine

data Coroutine s m r = Coroutine { resume :: m (St s m r) }
data St s m r = Run (s (Coroutine s m r)) | Done r

instance (Functor s,Functor m) => Functor (Coroutine s m) where
  fmap f = Coroutine . fmap (fmap f) . resume

instance (Functor s,Functor m) => Functor (St s m) where
  fmap f (Done r) = Done (f r)
  fmap f (Run s ) = Run (fmap (fmap f) s)

这个实例需要对s和m类型的Functor实例。我们可以使用Yoneda或CoYoneda来消除它们吗?基本上自动:

data Coroutine s m r = Coroutine { resume :: CoYoneda m (St s m r) }
data St s m r = Run (CoYoneda s (Coroutine s m r)) | Done r

instance Functor (Coroutine s m) where
  fmap f = Coroutine . fmap (fmap f) . resume

instance Functor (St s m) where
  fmap f (Done r) = Done (f r)
  fmap f (Run s ) = Run (fmap (fmap f) s)

但现在,由于我使用CoYoneda,你将需要Functor实例为s和m,以提取s和m类型从您的Coroutine。那么有什么意义呢?

mapCoYoneda :: (forall a . f a -> g a) -> CoYoneda f a -> CoYoneda g a
mapCoYoneda phi (CoYoneda mp fb) = CoYoneda mp (phi fb)

好吧,如果我们有一个从我们的f到g的自然转换,它实例化Functor,然后我们可以应用它在结尾以提取我们的结果。这个结构映射将仅应用一次,然后,在从CoYoneda评估时,构成的fmapped函数的整个栈将命中结果。

你可能想玩Yoneda的另一个原因是,有时可能得到Monad实例为Yoneda f即使当f甚至不是一个Functor。例如

newtype Endo a = Endo { appEndo :: a -> a }

-- YEndo ~ Yoneda Endo
data YEndo a = YEndo { yEndo :: (a -> b) -> (b -> b) }

instance Functor YEndo where
  fmap f y = YEndo (ab -> yEndo y (ab . f))

instance Monad YEndo where
  return a = YEndo (ab _ -> ab a)
  y >>= f  = YEndo (ab b -> yEndo y (a -> yEndo (f a) ab b) b)

其中我们通过将YEndo视为CPS转换的Maybe monad来获得Monad YEndo的定义。

这种工作显然不是有用的,如果s必须离开一般,但如果实例化Coroutine具体的话可能是有益的。这个例子直接从爱德华Kmett的帖子Free Monads for Less 2。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读