如何设计一个接受所有域的部分函数,​​但依赖于某些状态?

时间:2014-12-19 16:49:00

标签: scala functional-programming

与函数式编程相关的问题。

“一行代码值千言万语”,所以:

class Entry {
  var entryOrderId: Option[Int]
  def closeEntry(closeOrder: Order) = {
    require(entryOrderId.isDefined)
    ...
  }
}

问题:为了关闭一个条目,必须定义entryOrderId。我不想抛出异常(使用'require'函数)并且我不想返回Try(成功/失败)对象,因为调用者不期望任何返回值。你会如何设计这个功能?

(N.b:我标记了Scala,但语言不是这里的问题......)

2 个答案:

答案 0 :(得分:3)

根据您的要求,如果来电者真的不关心结果,那么您可以在foreach上使用entryOrderId。因此,只有在定义entryOrderId时才会调用内部块。

class Entry {
  var entryOrderId: Option[Int]
  def closeEntry(closeOrder: Order) = entryOrderId foreach { id =>
    // do something with the `id` ...
  }
}

答案 1 :(得分:2)

如果在没有entryOrderId的条目上调用closeEntry是一个编程错误,它甚至不应该编译。为了强制执行此操作,我将在Entry上添加一个类型参数。这将使状态更改变得明确,以及closeEntry对条目状态的约束。

class Order
case class Entry[T <: Option[Int]](entryOrderId: T) {
  def closeEntry(closeOrder: Order)(implicit ev: T =:= Some[Int]): Unit = {
    entryOrderId.get + 42
  }
}

如果您在Entry[Option[Int]]Entry[None.type]上调用closeEntry,编译器会抱怨:

scala> Entry(Some(42)).closeEntry(new Order)

scala> Entry(None).closeEntry(new Order)
<console>:11: error: Cannot prove that None.type =:= Some[Int].
              Entry(None).closeEntry(new Order)
                                    ^

这个解决方案远非完美:

  • 条目的类型不必要地冗长(Int太多)
  • 我不知道如何使用模式匹配从Entry[Some[Int]]中提取Entry[Option[Int]],所以一旦获得Entry[Some[Int]]
  • 我没看到的其他问题:p

在所有这些变化中,我能找到的最好的是:

import scala.language.higherKinds

class Order
case class Entry[T[_]](entryOrderId: T[Int]) {
  def closeEntry(order: Order)(implicit withId: WithId[T]): Unit = {
    withId.getId(this) + 42
  }
}
implicit object Entry extends HasId[Some] {
  def getId(entry: Entry[Some]): Int = entry.entryOrderId.get
}

trait WithId[T[_]] {
  def getId(entry: Entry[T]): Int
}

(更好,因为类型现在有点短 - Entry[Some]而不是Entry[Some[Int]]


另一个更简单的解决方案是:

sealed trait Entry
case class EntryWithId(val entryOrderId: Int) extends Entry {
  def closeEntry(closeOrder: Order): Unit = {
    ...
  }
}
class NewEntry() extends Entry

唯一的问题是你必须为其他最终字段复制粘贴构造函数。