用猫“组成”类人动物的惯用方法?

时间:2018-07-16 10:02:32

标签: scala functional-programming scala-cats monoids

我想用猫来“组成”两个类人动物。如果存在已定义的Monoid[(A, A) => Int],那么我希望能够使用Monoid[Preference[A]]的{​​{1}}和combine方法来创建empty。我在这里宽松地使用了“合成”一词,因为我不确定我要进行的转换是否准确地称为合成。

这是我目前的尝试...

Monoid[(A, A) => Int]

...这可以编译,但是我想知道是否有使用猫的惯用解决方案。

似乎应该可以以某种方式将import cats._ import cats.implicits._ trait Preference[A] extends Order[A] object Preference { def from[A](f: (A, A) => Int): Preference[A] = { new Preference[A] { def compare(a1: A, a2: A): Int = { f(a1, a2) } } } def monoid[A](implicit ev: Monoid[(A, A) => Int]): Monoid[Preference[A]] = { new Monoid[Preference[A]] { def combine(p1: Preference[A], p2: Preference[A]): Preference[A] = { new Preference[A] { def compare(a1: A, a2:A): Int = { ev.combine(p1.compare, p2.compare)(a1, a2) } } } def empty: Preference[A] = { from(ev.empty) } } } } Monoid[(A,A) => Int]组合器组成,该组合器采用from并返回f:(A, A) => Int以创建Preference[A]但我不知道该怎么做。

我看过这篇SO帖子,其中讨论了使用Monoid[Preference[A]]组合器来编写类半体词,这不是我想要的。

1 个答案:

答案 0 :(得分:1)

我不知道cats中直接内置的任何内容。

似乎您在Preference[A](A, A) => Int之间具有同构,并且您只想将类半球形结构从(A, A) => Int转移到Preference[A]。可以一般地用任意类型AB来表示:

def fromIsomorphicMonoid[A, B](
  forward: A => B,
  inverse: B => A
)(implicit aMon: Monoid[A]): Monoid[B] = new Monoid[B] {
  def combine(b1: B, b2: B): B = 
    forward(aMon.combine(inverse(b1), inverse(b2)))
  def empty: B = forward(aMon.empty)
}

使用此帮助程序方法,您在monoid中的Preference变为:

def monoid[A](implicit ev: Monoid[(A, A) => Int]): Monoid[Preference[A]] =
  fromIsomorphicMonoid(
    from, 
    (p: Preference[A]) => (x:A, y:A) => p.compare(x, y)
  )

完整的可编译示例(没有任何依赖性):

trait Monoid[X] {
  def empty: X
  def combine(x: X, y: X): X
}

trait Order[A] {
  def compare(a1: A, a2: A): Int
}

def fromIsomorphicMonoid[A, B](
  forward: A => B,
  inverse: B => A
)(implicit aMon: Monoid[A]): Monoid[B] = new Monoid[B] {
  def combine(b1: B, b2: B): B = 
    forward(aMon.combine(inverse(b1), inverse(b2)))
  def empty: B = forward(aMon.empty)
}

trait Preference[A] extends Order[A]  

object Preference {

  def from[A](f: (A, A) => Int): Preference[A] = {
    new Preference[A] {
      def compare(a1: A, a2: A): Int = {
        f(a1, a2)
      }
    }
  }

  def monoid[A](implicit ev: Monoid[(A, A) => Int])
  : Monoid[Preference[A]] = fromIsomorphicMonoid(
    from, 
    (p: Preference[A]) => (x:A, y:A) => p.compare(x, y)
  )
}