Scala,使用typelevel';s代数

Scala,使用typelevel';s代数,scala,algebra,Scala,Algebra,前提:我是Scala的新手 我想定义一个数学意义上的a:一个偏序,其中每两个元素都有一个连接或上限。元素不必是数字,但必须定义偏序关系 我需要构建的晶格如下(): 其中儿童

前提:我是Scala的新手

我想定义一个数学意义上的a:一个偏序,其中每两个元素都有一个连接或上限。元素不必是数字,但必须定义偏序关系

我需要构建的晶格如下():

其中
儿童
父母<祖父母
叔叔<祖父母
,但不
儿童<叔叔


我从中发现了这个特点。使用此库是否可以指定此结构?

您的关系图只允许(无界连接)半晶格。您可以使用
cats内核中的
半格
(它是
代数
的依赖项)或
代数
中的
连接半格
(唯一的区别是该操作称为“连接”)

具有有界s-l的。需要“最小”元素,在您的情况下,
祖父母
是“最大”元素


我将展示一个示例实现和一些使用示例。首先,让我们声明我们的类型:

sealed trait Rel
case object Grandparent extends Rel
case object Parent extends Rel
case object Child extends Rel
case object Uncle extends Rel
和类型类实例:

import cats.kernel._

// Using Scala 2.12 Single Abstract Method syntax
implicit val relSemilattice: Semilattice[Rel] = {
  case (a, b) if a == b => a
  case (Grandparent | Uncle, _) | (_, Grandparent | Uncle) => Grandparent
  case (Child, b) => b
  case (a, Child) => a
}
要获得偏序,您需要
Eq
实例。这一个是
\u==\ u
,这对于单例对象来说是完全合适的

implicit val relEq: Eq[Rel] = Eq.fromUniversalEquals
因为我们的操作是“join”,所以使用了方法
asJoinPartialOrder

implicit val relPartialOrder = relSemilattice.asJoinPartialOrder
一旦我们得到偏序,比较运算符就只需要一个导入。尽管有一个陷阱:

import cats.syntax.partialOrder._

// Parent < Grandparent // <- this will not compile
// You have to "upcast" to same type to use partial order syntax:

(Parent: Rel) < (Grandparent: Rel)

// for brevity, let's just quickly upcast 'em all in a fresh variables
val List(grandparent, parent, child, uncle) = List[Rel](Grandparent, Parent, Child, Uncle)
您可以使用
pmin
pmax
从两个元素中获取最小值/最大值,如果无法比较元素,则使用
Some
,或
None

assert((child pmin uncle) == None)
另一件事,晶格形成了一个
半群
,因此您可以使用“tie fighter”plus来获得连接:

import cats.syntax.semigroup._
assert((parent |+| uncle) == grandparent)
assert((child |+| parent) == parent)

也可以定义不带半格的偏序:

implicit val relPartialOrder: PartialOrder[Rel] = {
  case (a, b) if a == b => 0.0
  case (Grandparent, _) => 1.0
  case (_, Grandparent) => -1.0
  case (_, Uncle) | (Uncle, _) => Double.NaN
  case (Child, _) => -1.0
  case (_, Child) => 1.0
}
您不需要使用
Eq
,但不需要半群合并运算符

assert((child pmin uncle) == None)
import cats.syntax.semigroup._
assert((parent |+| uncle) == grandparent)
assert((child |+| parent) == parent)
implicit val relPartialOrder: PartialOrder[Rel] = {
  case (a, b) if a == b => 0.0
  case (Grandparent, _) => 1.0
  case (_, Grandparent) => -1.0
  case (_, Uncle) | (Uncle, _) => Double.NaN
  case (Child, _) => -1.0
  case (_, Child) => 1.0
}