Scala: что-то вроде Option (Некоторые, Нет), но с тремя состояниями: Некоторые, Нет, Неизвестно - PullRequest
6 голосов
/ 15 ноября 2009

Мне нужно вернуть значения, и когда кто-то запрашивает значение, скажите им одну из трех вещей:

  1. Вот значение
  2. Нет значения
  3. У нас нет информации об этом значении (неизвестно)

вариант 2 слегка отличается от варианта 3. Пример:

val radio = car.radioType
  1. мы знаем значение: вернем тип радио, скажем "пионер"
  2. б. нет значения: return None
  3. с. нам не хватает данных об этом автомобиле, мы не знаем, есть ли у него радио или нет

Я думал, что могу расширить Scala's None и создать Unknown, но это кажется невозможным.

предложения?

спасибо!

Обновление:

В идеале я хотел бы иметь возможность писать такой код:

car.radioType match { 
   case Unknown => 
   case None => 
   case Some(radioType : RadioType) => 
}

Ответы [ 6 ]

13 голосов
/ 15 ноября 2009

Вот базовая реализация. Возможно, вы захотите взглянуть на источник для класса Option для некоторых наворотов:

package example

object App extends Application {
  val x: TriOption[String] = TriUnknown

  x match {
    case TriSome(s) => println("found: " + s)
    case TriNone => println("none")
    case TriUnknown => println("unknown")
  }
}

sealed abstract class TriOption[+A]
final case class TriSome[+A](x: A) extends TriOption[A]
final case object TriNone extends TriOption[Nothing]
final case object TriUnknown extends TriOption[Nothing]
8 голосов
/ 16 ноября 2009

Не говорите никому, что я предложил это, но вы всегда можете использовать null для Unknown вместо написания нового класса.

car.radioType match { 
   case null => 
   case None => 
   case Some(radioType : RadioType) => 
}
5 голосов
/ 16 ноября 2009

Вы можете взять кое-что из Lift: the Box. Он имеет три состояния: Полный, Отказ и Пустой. Кроме того, Empty и Failure наследуются от EmptyBox.

4 голосов
/ 15 ноября 2009

Вы можете использовать scala.Either. Используйте Left для исключительного значения и Right для ожидаемого значения, которое может быть опцией в этом случае:

scala> type Result = Either[String, Option[String]]
defined type alias Result

scala> val hasValue: Result = Right(Some("pioneer"))
hasValue: Result = Right(Some(pioneer))

scala> val noValue: Result = Right(None)
noValue: Result = Right(None)

scala> val unknownValue = Left("unknown")
unknownValue: Left[java.lang.String,Nothing] = Left(unknown)
2 голосов
/ 15 ноября 2009

Вы можете создать свой собственный с тремя возможностями. Или один из ваших типов car.radioType, который вы могли бы иметь неизвестным, а затем использовать охранники в вашем деле для его обработки. Если вы катите свой собственный, вы должны также включить черту Product. Атрибут lifweb имеет тип Box, который является опцией close, которая позволяет выполнять full, empty и erorr.

0 голосов
/ 30 ноября 2017

Я сделал что-то похожее, чтобы классифицировать 3 типа строк в данном файле, данная строка может быть, например, Float для строки заголовка, Long для строки в середине (строка) или String для трейлерной линии. Также isHeader, isRow и isTrailer могут использоваться, чтобы узнать, какой из них. Надеюсь, поможет:

sealed abstract class HRT[+H, +R, +T] {
  val isHeader: Boolean
  val isRow: Boolean
  val isTrailer: Boolean
}

final case class Header[+H, +R, +T](h: H) extends HRT[H, R, T] {
  override val isHeader: Boolean = true
  override val isRow: Boolean = false
  override val isTrailer: Boolean = false
}

final case class Row[+H, +R, +T](r: R) extends HRT[H, R, T] {
  override val isHeader: Boolean = false
  override val isRow: Boolean = true
  override val isTrailer: Boolean = false
}

final case class Trailer[+H, +R, +T](t: T) extends HRT[H, R, T] {
  override val isHeader: Boolean = false
  override val isRow: Boolean = false
  override val isTrailer: Boolean = true
}

object Demo {
  def getEntries(): Seq[HRT[Float, Long, String]] =
    List(
      Header(3.14f),
      Row(42),
      Trailer("good bye")
    )

  val entries = getEntries()

  entries.foreach {
    case Header(f) => printf("header: %f\n", f)
    case Row(l) => printf("row: %d\n", l)
    case Trailer(s) => printf("trailer: %s\n", s)
  }
}
...