Scala 定义函子时,如何抽象第二个类型参数?

Scala 定义函子时,如何抽象第二个类型参数?,scala,functional-programming,functor,scala-cats,Scala,Functional Programming,Functor,Scala Cats,使用Scala和Cats学习地道的FP。我有以下代码 package org.economicsl.mechanisms import cats._ import cats.implicits._ trait Preference[-A] { self => def compare(a1: A, a2: A): Int final def ordering[A1 <: A]: Ordering[A1] = { new Ordering[A1] {

使用Scala和Cats学习地道的FP。我有以下代码

package org.economicsl.mechanisms

import cats._
import cats.implicits._

trait Preference[-A] {
  self =>

  def compare(a1: A, a2: A): Int

  final def ordering[A1 <: A]: Ordering[A1] = {
    new Ordering[A1] {
      def compare(a1: A1, a2: A1): Int = {
        self.compare(a1, a2)
      }
    }
  }

}


object Preference {

  implicit val contravariant: Contravariant[Preference] = {
    new Contravariant[Preference] {
      def contramap[A, B](fa: Preference[A])(f: B => A): Preference[B] = {
        new Preference[B] {
          def compare(b1: B, b2: B): Int = {
            fa.compare(f(b1), f(b2))
          }
        }
      }
    }
  }

  /** Defines a preference for a particular alternative. */
  def particular[A](alternative: A): Preference[A] = {
    new Preference[A] {
      def compare(a1: A, a2: A): Int = {
        if ((a1 != alternative) & (a2 == alternative)) {
          -1
        } else if ((a1 == alternative) & (a2 != alternative)) {
          1
        } else {
          0
        }
      }
    }
  }

}

/** Base trait defining a generic social welfare function.
  *
  * A social welfare function aggregates the preferences of individual agents
  * into a common preference ordering.
  */
trait SocialWelfareFunction[-CC <: Iterable[P], +P <: Preference[A], A]
  extends (CC => P)


/** Companion object for the `SocialWelFareFunction` trait. */
object SocialWelfareFunction {

  val setInvariant: Invariant[({ type F[A] = SocialWelfareFunction[Set[Preference[A]], Preference[A], A] })#F] = {
    new Invariant[({ type F[A] = SocialWelfareFunction[Set[Preference[A]], Preference[A], A] })#F] {
      def imap[A, B](fa: SocialWelfareFunction[Set[Preference[A]], Preference[A], A])(f: A => B)(g: B => A): SocialWelfareFunction[Set[Preference[B]], Preference[B], B] = {
        new SocialWelfareFunction[Set[Preference[B]], Preference[B], B] {
          def apply(preferences: Set[Preference[B]]): Preference[B] = {
            fa(preferences.map(pb => pb.contramap(f))).contramap(g)
          }
        }
      }
    }
  }

  val seqInvariant: Invariant[({ type F[A] = SocialWelfareFunction[Seq[Preference[A]], Preference[A], A] })#F] = {
    new Invariant[({ type F[A] = SocialWelfareFunction[Seq[Preference[A]], Preference[A], A] })#F] {
      def imap[A, B](fa: SocialWelfareFunction[Seq[Preference[A]], Preference[A], A])(f: A => B)(g: B => A): SocialWelfareFunction[Seq[Preference[B]], Preference[B], B] = {
        new SocialWelfareFunction[Seq[Preference[B]], Preference[B], B] {
          def apply(preferences: Seq[Preference[B]]): Preference[B] = {
            fa(preferences.map(pb => pb.contramap(f))).contramap(g)
          }
        }
      }
    }
  }
}
package org.economicsl.mechanism
进口猫_
进口猫_
特质偏好[-A]{
自我=>
def比较(a1:A,a2:A):整数
最终def订购[A1 A]:首选项[B]={
新优惠[B]{
def比较(b1:B,b2:B):整数={
fa.比较(f(b1),f(b2))
}
}
}
}
}
/**定义特定备选方案的首选项*/
定义特定[A](备选方案:A):首选项[A]={
新优惠[A]{
def比较(a1:A,a2:A):整数={
如果((a1!=备选方案)和(a2==备选方案)){
-1
}否则如果((a1=备选方案)和(a2!=备选方案)){
1.
}否则{
0
}
}
}
}
}
/**定义一般社会福利函数的基本特征。
*
*社会福利函数集合了个体代理人的偏好
*变成一个共同的偏好排序。
*/
特质社会福利函数[-CC B)(g:B=>A):社会福利函数[Set[Preference[B]],Preference[B],B]={
新的社会福利函数[Set[Preference[B]],Preference[B],B]{
def应用(首选项:设置[首选项[B]]):首选项[B]={
fa(preferences.map(pb=>pb.contramap(f))).contramap(g)
}
}
}
}
}
val Seq不变量:不变量[({type F[A]=社会福利函数[Seq[Preference[A]],Preference[A],A]})#F]={
新的不变量[({type F[A]=社会福利函数[Seq[Preference[A]],Preference[A],A]})#F]{
定义imap[A,B](fa:SocialWelfalFunction[Seq[Preference[A]],Preference[A],A])(f:A=>B)(g:B=>A):SocialWelfalFunction[Seq[Preference[B]],Preference[B],B]={
新的社会福利函数[Seq[Preference[B]],Preference[B],B]{
def应用(首选项:顺序[首选项[B]]):首选项[B]={
fa(preferences.map(pb=>pb.contramap(f))).contramap(g)
}
}
}
}
}
}
SocialWelfareFunction
的伴随对象中,我定义了两个不变函子。实现几乎相同:第一个函子使用
Set
存储
首选项[a]
实例,第二个函子使用
Seq


有没有办法对存储首选项的集合类型进行抽象?如果解决方案需要,我愿意包含其他类型级别的依赖项。

您可以这样做:

  def invariant[C[X] <: Iterable[X] : Functor]: Invariant[({ type F[A] = SocialWelfareFunction[C[Preference[A]], Preference[A], A] })#F] = {
    new Invariant[({ type F[A] = SocialWelfareFunction[C[Preference[A]], Preference[A], A] })#F] {
      def imap[A, B](fa: SocialWelfareFunction[C[Preference[A]], Preference[A], A])(f: A => B)(g: B => A): SocialWelfareFunction[C[Preference[B]], Preference[B], B] = {
        new SocialWelfareFunction[C[Preference[B]], Preference[B], B] {
          def apply(preferences: C[Preference[B]]): Preference[B] = {
            fa(Functor[C].map(preferences)(pb => pb.contramap(f))).contramap(g)
          }
        }
      }
    }
  }
令人恼火的是,它们似乎没有用于
集合
序列
的内置
函子
,但它们很容易定义自己:

  private[this] implicit val setFunctor = new Functor[Set] {
    override def map[A, B](s: Set[A])(f: A => B): Set[B] = s.map(f)
  }

  val setInvariant = invariant[Set]

什么是
首选项
,为什么它上面有
contracmap
?是否可以添加一些存根实现以使代码段可编译?能否解释类型参数限制
[C[X]
C
必须是
Iterable
的子类,因为
SocialWelfareFunction
的类型限制。然后
:Functor
确保您有一个隐式
Functor[C]
,它使您能够映射到
C
类型。如果没有它,您可以尝试使用
Iterable
map
方法,但随后您会得到一个
Iterable
返回,而不是
C
。可能有一种方法可以使用标准库的
CanBuildFrom
东西来实现,但因为您已经深入到cats,我认为这样做更容易/更干净。明白。我更喜欢您的解决方案,而不是使用
隐式cbf:CanBuildFrom
构造,因为我认为新的集合API将来将不再使用
CanBuildFrom
  private[this] implicit val setFunctor = new Functor[Set] {
    override def map[A, B](s: Set[A])(f: A => B): Set[B] = s.map(f)
  }

  val setInvariant = invariant[Set]