簡體   English   中英

Scala中嵌套的Monads組成

[英]Nested Monads Composition in Scala

這是一個代碼示例:

import cats.data.Reader

trait Configuration {  

  type FailFast[A] = Either[List[String], A]

  def getValue(name: String)(map: Map[String, String]): FailFast[String] =
    map.get(name)
      .toRight(List(s"$name field not specified"))

  type PropReader[A] = Reader[Map[String, String], A]
  def propReader(name:String): PropReader[FailFast[String]] =
    Reader(map => validation.getValue(name)(map))

  type OptionalValue[A] = PropReader[FailFast[Option[A]]]
  //how to use propReader(Configuration.NEW_EVENT)
  //inside of 'event' to return 'OptionalValue':?
  def event:OptionalValue[String] = ???
}      

object Configuration extends Configuration {
  final val NEW_EVENT = "event.unique"
}

無法獲取如何通過以下內容來實現事件: propReader(Configuration.NEW_EVENT)

如果選項多於1個,那么最好考慮所有選項。

感謝@Travis Brown進行更新 ,我將以這種方式實現它。 這是更新的實現:

  import cats.instances.list._ //for monoid
  import cats.instances.either._

  type FailFast[A] = Either[List[String], A]
  type PropReaderT[A] = ReaderT[FailFast, Map[String, String], A]
  type OptionalReaderT[A] = ReaderT[FailFast, Map[String, String], Option[A]]

  def getValue(name: String)(map: Map[String, String]): FailFast[String] =
    map.get(name).toRight(List(s"$name field not specified"))

  def propReader(name: String): PropReaderT[String] =
    ReaderT(getValue(name))

  def value2Option(value:String):Option[String] =
    if (value == null || value.isEmpty) Option.empty
    else Some(value)

  def event: OptionalReaderT[String] =
    propReader(Configuration.KEY1)
      .map(result => value2Option(result))

這與Travis Brown的實現之間的區別:我需要看到在映射中沒有鍵(這是一個錯誤,並且我需要對其進行清晰的錯誤描述)與鍵存在但鍵值存在的情況之間的區別。 null或空字符串。 因此,它與以Maps.get返回Option的方式不同。 所以我不能擺脫FailFast

希望對某人有用。

最簡單的方法是將結果映射到結果,將失敗升級為成功None

import cats.data.Reader

trait Configuration {
  type FailFast[A] = Either[List[String], A]
  type PropReader[A] = Reader[Map[String, String], A]
  type OptionalValue[A] = PropReader[FailFast[Option[A]]]

  def getValue(name: String)(map: Map[String, String]): FailFast[String] =
    map.get(name).toRight(List(s"$name field not specified"))

  def propReader(name:String): PropReader[FailFast[String]] =
    Reader(getValue(name))

  def event: OptionalValue[String] = propReader(Configuration.NEW_EVENT).map(
    result => Right(result.right.toOption)
  )
}      

object Configuration extends Configuration {
  final val NEW_EVENT = "event.unique"
}

我認為值得重新考慮該模型。 任何時候只要您擁有一個看起來像A => F[B]的函數(就像在地圖中查找),您就可以將其表示為ReaderT[F, A, B] ,它為您提供了更好的組合方式-而不是例如,通過兩層進行映射,您只有一層。

ReaderT方法還使更改F (通過mapK )更好mapK 例如,假設像您的示例中那樣,您通常希望與在FailFast上下文中返回其值的讀取器一起工作,但有時需要切換到Option上下文。 看起來像這樣:

import cats.~>
import cats.arrow.FunctionK
import cats.data.ReaderT

trait Configuration {
  type FailFast[A] = Either[List[String], A]
  type PropReader[A] = ReaderT[FailFast, Map[String, String], A]
  type OptionalReader[A] = ReaderT[Option, Map[String, String], A]

  private def eitherToOption[A](either: FailFast[A]): Option[A] =
    either.right.toOption

  def getValue(name: String)(map: Map[String, String]): FailFast[String] =
    map.get(name).toRight(List(s"$name field not specified"))

  def propReader(name: String): PropReader[String] =
    ReaderT(getValue(name))

  def event: OptionalReader[String] =
    propReader(Configuration.NEW_EVENT).mapK(FunctionK.lift(eitherToOption))
}      

object Configuration extends Configuration {
  final val NEW_EVENT = "event.unique"
}

OptionalReader這里是不完全一樣的OptionalValue ,因為它不包括FailFast層,但這層是在你的代碼多余的,因為缺失值在代表Option層,所以OptionReader做法很可能是更合適。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM