2017-06-18 52 views
0

我已经和ADT函子基本上是一个包装过Function1斯卡拉:如何使用多类型参数特征

case class Abstract[M[_], A, B](f:M[A] => M[B]) { 
    def fn: M[A] => M[B] = { case x: M[A] => f(x) } 
} 

我要地图了这些,所以我定义了一个函子,像这样:

trait AbstractAPI[E] { 
    type AbsO[T] = Abstract[List, E, T] 
    // type AbsO[T] = Abstract[List, _, T] => does not work (?) 

    implicit val abstractO: Functor[AbsO] = new Functor[AbsO] { 
     def map[A, B](fa: AbsO[A])(f: A => B): AbsO[B] = { 
      new Abstract(fa.fn andThen { x: List[A] => x.map{ y => f(y) } }) 
     } 
    } 
} 

现在,实际上映射了一个抽象的,我需要AbstractAPI[Int],像

case object IntAbstractAPI extends AbstractAPI[Int] 

object A { 
    import IntAbstractAPI._ 

    val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } } 
    val hey = (new Abstract(f)).map{ x => x.toInt } 
} 

object A extends AbstractAPI[Int] { 

    val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } } 

    // FINALLY! 
    val res = (new Abstract(f)).map{ x => x.toInt }.map{ _.toFloat + 10f } 
    // Abstract[List, Int, Float] = Abstract(<function1>) 
} 

然而,在这种模式中,我不得不定义每个可能的E情况的对象。这里是我的问题:

  1. 这是使用Functors的正确方法吗?
  2. 我如何可以自动的情况下创建对象的每一个可能的E(或使编译器推断呢?)

编辑1: 进一步澄清:上述实施工作,但是这一次不会:

object A extends AbstractAPI { 

    val f:List[Int] => List[String] = { case x: List[Int] => x.map{ _.toString.toLowerCase } } 

    val res = (new Abstract(f)).map{ x => x.toInt }.map{ _.toFloat + 10f } 
    // Abstract[List, Int, Float] = Abstract(<function1>) 
} 

给出编译错误:

value map is not a member of Abstract[List,Int,String] 

我想这是因为补偿iler无法为Abstract[List,Int,String]派生函子吗?

+0

这是一个有点难以理解。编译器无法知道如何将'_'转换为'T',而不会被告知如何,对吗? – erip

+0

基本上我想创建一个函数的包装,以这种方式,我可以映射到包装与其他函数来创建(组合)函数的新包装 – ixaxaar

+0

这有帮助吗? – ixaxaar

回答

1

可以得到的函子输入你不关心的参数。

import cats.Functor 
import cats.syntax.functor._ 

我会重命名AbstractX秒类型参数,它会帮助

case class Abstract[M[_], X, A](f: M[X] => M[A]) // forget the fn bit for now 

您可以创建类型类的实例,不仅有val,而且还带有def。允许使用类型参数,也可以使用其他隐式(但只是隐式)参数。

type Abs1[X] = ({ type L[A] = Abstract[List, X, A] }) 

/*implicit*/ def abstract1[X]: Functor[Abs1[X]#L] = new Functor[Abs1[X]#L] { 
override def map[A, B](fa: Abstract[List, X, A])(f: A => B): Abstract[List, X, B] = 
     Abstract(mx => fa.f(mx).map(f)) 
} 

如果map是你从List需要,您可以进一步概括为具有Functor实例的任何M[_]。将它放入Abstract的伴随对象中,可以在没有附加导入/继承/等的情况下找到它。

object Abstract { 
    // Abstract.MX[M, X]#L can be replaced with Abstract[M, X, ?] if you use kind-projector 
    type MX[M[_], X] = ({ type L[A] = Abstract[M, X, A] }) 

    implicit def genericFunctor[M[_]: Functor, X] = new Functor[MX[M, X]#L] { 
    override def map[A, B](fa: Abstract[M, X, A])(f: A => B): Abstract[M, X, B] = 
     Abstract(mx => fa.f(mx).map(f)) // the implementation is the same 
    } 
} 

和它的作品,如果导入的实例为无论你M[_]

assert { 
    import cats.instances.list._ // get Functor[List] 

    // map is automatically picked up from Functor[Abstract[List, Int, ?]] 
    Abstract(identity[List[Int]]) 
    .map(Vector.range(0, _)) 
    .map(_.mkString("")) 
    .f(List(1, 2, 3)) == List("0", "01", "012") 
} 

assert { 
    import cats.instances.option._ 

    Abstract(identity[Option[Int]]) 
    .map(_ min 42) 
    .map(i => Range(i, i + 3)) 
    .f(Some(11)) == Some(Range(11, 14)) 
} 

你可以尝试代码there

0

回答你的第二个问题,你可以试试这个隐含AbstractAPI[T]厂:

implicit def abstractAPI[T]: AbstractAPI[T] = new AbstractAPI[T] {} 

AbstractAPI[T]任何所需的隐含证据应该工作,如:

def f[T : AbstractAPI]: Unit =() 
f