定义仿函数时如何抽象第二个类型参数?
How to abstract over a second type parameter when defining functors?
使用 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)
}
}
}
}
}
}
在 SocialWelfareFunction
的伴随对象中,我定义了两个不变仿函数。这些实现 几乎 相同:第一个函子使用 Set
来存储 Preference[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)
}
}
}
}
}
然后对于 cats 具有 Functor
的类型,您可以这样做:
val listInvariant = invariant[List]
令人讨厌的是,他们似乎没有为 Set
和 Seq
内置的 Functor
s,但他们很容易定义自己:
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]
使用 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)
}
}
}
}
}
}
在 SocialWelfareFunction
的伴随对象中,我定义了两个不变仿函数。这些实现 几乎 相同:第一个函子使用 Set
来存储 Preference[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)
}
}
}
}
}
然后对于 cats 具有 Functor
的类型,您可以这样做:
val listInvariant = invariant[List]
令人讨厌的是,他们似乎没有为 Set
和 Seq
内置的 Functor
s,但他们很容易定义自己:
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]