如何阻止Option-ality感染一切

时间:2017-07-30 16:29:08

标签: scala types

我是Scala的新手。我想要一个表达类似于以正整数测量的坐标的类。 (这是一个简化的例子;请不要指出是否存在其他坐标类;假设我真的需要一个新类。)

我的第一次尝试是简单地将require(x >= 0 && y >= 0)放入课堂,但我的团队成员不喜欢这会引发异常。

我的第二次尝试返回Option[Coordinate]。所以现在每次我创建这样一个坐标时,我都有4行,我通常只有一行。更糟糕的是,Option ality感染了我正在构建这些坐标的所有内容。现在我有Option[Row]Option[Rectangle]Option[Cube]Option[Report] ......

其他人建议我通过建立一个始终为正的Natural数字类型来解决问题。但现在这推动了问题是从一个可能为负的常规整数中创建Natural

我是Scala的新手,但在我看来,如果

,选项,任何一个和尝试都有意义

(a)操作可能会失败,因为您正在进行I / O

(b)有一个合理的替代方案,缺少某些东西

似乎这些都没有抓住我在这里要做的事情,这实际上是为了防止某人在编码时犯了数学错误。

么?

2 个答案:

答案 0 :(得分:0)

  

在我看来,如果

,选项,任何一个和尝试都有意义

您提到的课程都负责某个效果。您在某些需要效果的上下文中描述它们是正确的,例如执行IO,或者与可能引发异常的方法(可能是Java API)交互,或者想要描述一个或多个操作可能会失败的操作链

我认为这可以归结为你想要去的兔子洞的深度。我的意思是Scala的强大之处在于它的类型系统,这就是你可以而且应该利用的优势。我同意你的观点,使用Option[Coordinate]并不自然,但对我来说当然不行。立即出现的问题是“我如何利用类型系统来帮助我只接受自然数?”。好吧,似乎其他人也和你有同样的担忧。

例如,有一个名为shapeless的库,其下面有一个代表自然数的Nat类型。例如,给出以下案例类:

import shapeless.Nat

case class Coordinate(x: Nat, y: Nat)

如果我使用自然数字创建它,一切都会编译:

def main(args: Array[String]): Unit = {
  val cord = Coordinate(1, 1)
}

但是一旦我给它一个非自然数,编译器会抱怨!

def main(args: Array[String]): Unit = {
  val cord = Coordinate(-1, 1)
}

使用:

Error:(13, 28) Expression -1 does not evaluate to a non-negative Int literal
   val cord = Coordinates(-1, 1)

IMO是你应该利用的类型系统的力量。如果您和您的团队愿意正确地对这些类型进行编码,那么您可以为您的团队和用户提供一个非常有力的保证:“如果这样编译,那就完成了您的意思。”

答案 1 :(得分:0)

你有一个非常好的问题。

  

我的第一次尝试是简单地将require(x> = 0&& y> = 0)放入   上课,但是我的团队成员并不喜欢这样做   异常。

那是对的。如果你选择这种方式,你必须以某种方式处理异常。

  

我是Scala的新手,但在我看来,选项,任何一个和尝试   如果有意义

     

(a)操作可能会失败,因为您正在进行I / O

     

(b)除了某种东西之外,还有一个合理的替代方案

半真的。如果您域中的不变量表示某个元素可能为空,那么您可以使用Option来表达该行为,并且您也可以获得表达性。特别是Option的使用并不局限于I / O操作。

在我解决(b)关注之前,让我解释一下。

Scala有上下文(我不会在这里使用'M-word')表示效果,正如@Yuval Itzchakov之前所说。那就是:你有一个值,它包含一些提供一些组合器的东西,并提供一些行为处理。 EitherTryOption就是其中的一个示例,当您选择使用时,您将承诺处理包含在这些上下文中的数据。它们的作用是你必须处理这种效果。

请记住,数据可能会产生影响:异常(TryEither),空值(Option),异步计算({{1 }}) 等等。您的代数将根据这些上下文进行编码,因为它可以帮助您处理预期的行为。

  

似乎这些都没有抓住我在这里尝试做的事,   这是为了防止出现数学错误的人   在他们的编码中。

那就是说,在你的具体情况下,抛弃无形的Future选项,不,编译器不支持你想要实现的目标。请查看this