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

scala – 如何实现Functor [数据集]

发布时间:2020-12-16 18:13:41 所属栏目:安全 来源:网络整理
导读:我正在努力如何创建Functor [Dataset]的实例…问题是当你从A映射到B时,编码器[B]必须在隐式范围内,但我不知道该怎么做. implicit val datasetFunctor: Functor[Dataset] = new Functor[Dataset] { override def map[A,B](fa: Dataset[A])(f: A = B): Dataset
我正在努力如何创建Functor [Dataset]的实例…问题是当你从A映射到B时,编码器[B]必须在隐式范围内,但我不知道该怎么做.

implicit val datasetFunctor: Functor[Dataset] = new Functor[Dataset] {
    override def map[A,B](fa: Dataset[A])(f: A => B): Dataset[B] = fa.map(f)
  }

当然这个代码抛出了一个编译错误,因为Encoder [B]不可用但我不能将Encoder [B]添加为隐式参数,因为它会改变map方法签名,我该如何解决这个问题?

解决方法

你不能马上申请f,因为你错过了编码器.唯一明显的直接解决方案是:带猫并重新实现所有接口,添加一个隐含的Encoder参数.我没有看到任何方法直接实现数据集的Functor.

然而,以下替代解决方案可能足够好.
你可以做的是为数据集创建一个包装器,它有一个没有隐式编码器的map方法,但是还有一个toDataset方法,最后需要Encoder.

对于这个包装器,你可以使用一个非常类似于所谓的Coyoneda结构(或Coyo?今天他们称之为什么?我不知道……)的结构.它本质上是一种为任意类型构造函数实现“自由函子”的方法.

这是一个草图(它与猫1.0.1编译,由假人取代了Spark特征):

import scala.language.higherKinds
import cats.Functor

/** Dummy for spark-Encoder */
trait Encoder[X]

/** Dummy for spark-Dataset */
trait Dataset[X] {
  def map[Y](f: X => Y)(implicit enc: Encoder[Y]): Dataset[Y]
}

/** Coyoneda-esque wrapper for `Dataset` 
  * that simply stashes all arguments to `map` away
  * until a concrete `Encoder` is supplied during the
  * application of `toDataset`.
  *
  * Essentially: the wrapped original dataset + concatenated
  * list of functions which have been passed to `map`.
  */
abstract class MappedDataset[X] private () { self =>
  type B
  val base: Dataset[B]
  val path: B => X
  def toDataset(implicit enc: Encoder[X]): Dataset[X] = base map path

  def map[Y](f: X => Y): MappedDataset[Y] = new MappedDataset[Y] {
    type B = self.B
    val base = self.base
    val path: B => Y = f compose self.path
  }
}

object MappedDataset {
  /** Constructor for MappedDatasets.
    * 
    * Wraps a `Dataset` into a `MappedDataset` 
    */
  def apply[X](ds: Dataset[X]): MappedDataset[X] = new MappedDataset[X] {
    type B = X
    val base = ds
    val path = identity
  }

}        

object MappedDatasetFunctor extends Functor[MappedDataset] {
  /** Functorial `map` */
  def map[A,B](da: MappedDataset[A])(f: A => B): MappedDataset[B] = da map f
}

现在,您可以将数据集ds包装到MappedDataset(ds)中,然后根据需要使用隐式MappedDatasetFunctor对其进行映射,然后在最后调用toDataset,您可以为最终结果提供具体的Encoder.

请注意,这会将map中的所有函数组合到一个spark阶段:它将无法保存中间结果,因为缺少所有中间步骤的编码器.

我还没有学过猫,我无法保证这是最惯用的解决方案.可能Coyoneda-esque已经在图书馆里了.

编辑:猫库中有Coyoneda,但它需要自然转换F~> G到一个仿函数G.不幸的是,我们没有数据集的Functor(这首先是问题).我上面的实现是:代替Functor [G],它需要在固定的X处的(不存在的)自然变换的单个态射(这是编码器[X]所用的).

(编辑:李大同)

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

    推荐文章
      热点阅读