代码之家  ›  专栏  ›  技术社区  ›  davidrpugh

用猫来“组合”独联体的惯用方法?

  •  1
  • davidrpugh  · 技术社区  · 7 年前

    我想用猫来“合成”两个独联体。如果存在定义的 Monoid[(A, A) => Int] ,然后我希望能够创建 Monoid[Preference[A]] 使用 combine empty 方法 幺半群[(a,a)=>整数] 是的。我在这里使用术语“构图”是松散的,因为我不确定我要做的转换是否准确地称为构图。

    这是我目前的尝试…

    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)
          }
        }
      }
    }
    

    …这是编译的,但是我想知道是否有一个更习惯的解决方案可以使用cats。

    似乎有可能以某种方式 Monoid[(A,A) => Int] from 需要一个 f:(A, A) => Int 并返回 Preference[A] 创建 幺半群[偏好[a]] 但我不知道怎么做。

    我见过这个 SO 讨论使用 product 这不是我想要的。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Andrey Tyukin    7 年前

    我不知道里面有什么 cats 直接的。

    你好像有一个同构 Preference[A] (A, A) => Int ,您只需将幺半群结构从 (a,a)=>整数 优先权 是的。这可以泛型地表示为任意类型 A B 以下内容:

    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)
    }
    

    有了这个helper方法, 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)
      )
    }
    
    推荐文章