簡體   English   中英

如何實現Functor [Dataset]

[英]How to implement Functor[Dataset]

我正在努力如何創建Functor[Dataset]的實例...問題是當你從A mapBEncoder[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 唯一明顯的直接解決方案是:帶cats並重新實現所有接口,添加一個隱含的Encoder參數。 我看不出有任何的方式來實現FunctorDataset 直接

然而 ,以下替代解決方案可能足夠好。 你可以做的是為數據集創建一個包裝器,它有一個沒有隱式Encodermap方法,但是還有一個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對其進行map ,然后在最后調用toDataset ,您可以為最終結果提供具體的Encoder

請注意,這會將map所有函數組合到一個spark階段:它將無法保存中間結果,因為缺少所有中間步驟的Encoder


我還沒有學過cats ,我無法保證這是最慣用的解決方案。 可能Coyoneda -esque已經在圖書館里了。

編輯:在貓庫中有Coyoneda ,但它需要將F ~> G自然轉換為仿函數G 不幸的是,我們沒有DatasetFunctor (首先是問題)。 我上面的實現是:代替Functor[G] ,它需要在固定的X處的(不存在的)自然變換的單個態射 (這是Encoder[X]所用的)。

暫無
暫無

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

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