scala中的类型安全多米诺骨牌

scala中的类型安全多米诺骨牌,scala,types,shapeless,Scala,Types,Shapeless,所以我正在尝试编写一个多米诺骨牌游戏服务器,我正在编写我的核心类型、磁贴和多米诺骨牌集,我突然想到,包括磁贴的类型信息将允许我编写一个简单得多的函数来创建多米诺骨牌链,由于我无法理解这一点,我已经多次开始并没有完成这个项目,希望有人能有一个简单的类型安全的tile表示,从而产生一个简单的domino链函数。原因是我目前的心理模型是多米诺骨牌游戏中的一块棋盘,它只是一个初始的棋盘和1-3个多米诺骨牌链,每个棋盘的开头都与初始棋盘上的点子相匹配 提前非常感谢,并为我问题中的任何不完善之处表示歉意 s

所以我正在尝试编写一个多米诺骨牌游戏服务器,我正在编写我的核心类型、磁贴和多米诺骨牌集,我突然想到,包括磁贴的类型信息将允许我编写一个简单得多的函数来创建多米诺骨牌链,由于我无法理解这一点,我已经多次开始并没有完成这个项目,希望有人能有一个简单的类型安全的tile表示,从而产生一个简单的domino链函数。原因是我目前的心理模型是多米诺骨牌游戏中的一块棋盘,它只是一个初始的棋盘和1-3个多米诺骨牌链,每个棋盘的开头都与初始棋盘上的点子相匹配

提前非常感谢,并为我问题中的任何不完善之处表示歉意

sealed case class DoubleSix[L >: Nat, R <: Nat](lPips: Int, rPips: Int) extends Tile[L, R]

object DoubleSixSet {
  val zeroZero: DoubleSix[_0, _0] = DoubleSix(0, 0)

}

正如您可能注意到的那样,将多米诺骨牌以不同的类型表达是很容易的:

sealed trait One
sealed trait Two
sealed trait Three
sealed trait Four
sealed trait Five
sealed trait Six

sealed trait Domino[A, B] extends Product with Serializable
object Domino {
    case object OneOne[One, One]
    case object OneTwo[One, Two]
    ... // the other types of dominoes
}
如果您想要有一个线性链,也很容易:

sealed trait Chain[A, B] extends Product with Serializable
object Chain {
  case class One[A, B](domino: Domino[A, B]) extends Chain[A, B]
  case class Prepend[A, B, C](head: Domino[A, B], tail: Chain[B, C]) extends Chain[A, C]
}
如果这不是线性的,事情就会变得棘手。你可能想转弯。实现这一点的方法不止一种:

xxyy

 yy
xx
 
xx
 yy

xx
 y
 y

 y
 y
xx
每一个都必须作为一个单独的案例来表达。如果您希望避免以下情况:

  f <- f tile would have to be over or under bb tile
aabbc  f
  e c
  edd
如果你想用类型来表达它,现在你有两个头部可以前置(一个尾部可以追加)。在游戏中,你可能会有更多的分支,因此你必须以某种方式表达这两个方面:你有多少分支,以及你想向哪一个分支添加新的磁贴。仍然可能,但会使代码更加复杂

例如,您可以使用某种HList(如果您使用的是shapeless)表示头部,并使用该表示提供隐式信息,告诉您要修改HList的哪个元素

然而,在这一点上,类型级编程的好处很小:您必须提前知道您的类型,动态添加新的分片会有困难,您必须以能够检索确切类型的方式保持状态,以便类型级证据能够工作

因此,我建议使用一种类型安全但更容易实现的方法:只需使用:


这仍然使创建“无效”domino链变得不可能。同时,添加新规则、扩展功能和在请求之间保持状态(您提到要构建服务器)将更容易。

是的,我的错误,正在修复
  f <- f tile would have to be over or under bb tile
aabbc  f
  e c
  edd
aab
  bdd
 cc
type Position = UUID

sealed trait Chain extends Product with Serializable
object Chain {
  // prevent user from accessing constructors and copy directly
  sealed abstract case class One private (
    domino: Domino,
    position: Position
  ) extends Chain
  sealed abstract case class PrependLine private (
    domino: Domino,
    position: Position,
    chain:  Chain
  )
  sealed abstract case class Branch private (
    chain1: Chain,
    chain2: Chain
  )

  def start(domino: Domino): Chain

  // check if you can add domino at this position, recursively rewrite tree
  // if needed to add it at the right branch or maybe even create a new branch
  def prepend(domino: Domino, to: Chain, at: Position): Either[Error, Chain]
}