"composing" 使用猫的幺半群的惯用方法?
Idiomatic approach to "composing" monoids using cats?
我想 "compose" 两个使用猫的幺半群。如果存在已定义的 Monoid[(A, A) => Int]
,那么我希望能够使用 Monoid[(A, A) => Int]
的 combine
和 empty
方法创建 Monoid[Preference[A]]
。我在这里松散地使用术语 "composing" 因为我不确定我想要做的转换是否准确地称为合成。
这是我目前的尝试...
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]
与需要 f:(A, A) => Int
和 returns 和 Preference[A]
的 from
组合器组合起来Monoid[Preference[A]]
但我不知道该怎么做。
我看过这个 SO post,它讨论了使用 product
组合器组合幺半群,这不是我想要的。
我不知道 cats
中有什么直接内置的。
看来您在 Preference[A]
和 (A, A) => Int
之间存在同构,您只是想将幺半群结构从 (A, A) => Int
转移到 Preference[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)
}
使用这个辅助方法,您在 Preference
中的 monoid
就变成了:
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)
)
}
我想 "compose" 两个使用猫的幺半群。如果存在已定义的 Monoid[(A, A) => Int]
,那么我希望能够使用 Monoid[(A, A) => Int]
的 combine
和 empty
方法创建 Monoid[Preference[A]]
。我在这里松散地使用术语 "composing" 因为我不确定我想要做的转换是否准确地称为合成。
这是我目前的尝试...
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]
与需要 f:(A, A) => Int
和 returns 和 Preference[A]
的 from
组合器组合起来Monoid[Preference[A]]
但我不知道该怎么做。
我看过这个 SO post,它讨论了使用 product
组合器组合幺半群,这不是我想要的。
我不知道 cats
中有什么直接内置的。
看来您在 Preference[A]
和 (A, A) => Int
之间存在同构,您只是想将幺半群结构从 (A, A) => Int
转移到 Preference[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)
}
使用这个辅助方法,您在 Preference
中的 monoid
就变成了:
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)
)
}