处理monad失败的地方?

时间:2015-03-11 16:30:48

标签: scala haskell

我想知道使用monads编写代码的最佳方法是什么(Option,Try,Either)。 我的第一印象是那些monad应该让我写逻辑并忽略错误,然后根据类型结果我会更好地知道发生了什么。 我举一个例子

val a:Option[Something] = list.get("key")

现在我可以操作我的价值,就像我用map和flatMap一样 在代码的最后,如果我有None,则意味着列表没有“密钥”。 此工作流程仅在您具有小逻辑时才有效。 但如果我有很多逻辑,我应该如何编写代码 即:

val server:Option[Server] = serverList.get("serverId")
val value:Option[Try[Value]] = serverList.map(serverId=>getDataFromServer(serverId))
val processedValue:Option[Try[Some[OtherValue]]] = value.map(server => server.map( value=> processValue(value))

现在处理错误时我会做类似的事情:

processedValueOption match { 
   case None=> .... // server is not identified
   case Some(Failure(e)) =>  //error to get value from server
   case .......
}

实际上我的类型让我知道代码末尾的错误是什么。 但是当你有很大的逻辑时,它就变成了非常复杂的类型。 您认为我应该如何编写代码?我在编写逻辑时是否应该处理错误以获得简单的类型?

2 个答案:

答案 0 :(得分:1)

Either可以成为此类案例的更好解决方案之一,

// Explicit errors
object MyErrors {
    trait MyError
    object ServerNotIdentifiedError extends MyError
    object CanNotGetValueFromServerError extends MyError
    object ValueProcessingFailedError extends MyError 
}

val server: Either[ Server, MyError ] = serverList.get("serverId").match {
  case Some( server ) => Left( server )
  case None => Right( ServerNotIdentifiedError )
}

// assuming getDataFromServer returns Try[ Value ]
val value:Either[ Value, MyError ] = getDataFromServer( serverId ) match {
  case Success( value ) => Left( value ),
  case Failure( ex ) => {
    ex.printStackTrace();
    Right( CanNotGetValueFromServerError )
  }  
}

// assuming processValue returns Try[ OtherValue ]
val processedValue: Either[ OtherValue, MyError ] = value match {
  case Left( value ) => processValue(value) match {
    case Success( otherValue ) => Left( otherValue )
    case Failure( ex ) => {
      ex.printStackTrace()
      Right( ValueProcessingFailedError )
    }
  }
  case _ => value
}

答案 1 :(得分:0)

在Haskell中,通常使用EitherEitherTExceptTEitherTExceptT是monad变换器并且几乎完全相同)。您可以将do表示法与其中任何一个一起用于将可能失败的操作串联起来,并获得最终结果或有关失败的信息。在某些情况下,可以使用Applicative运算符。例如,

f <$> e1 <*> e2 <*> e3

将计算e1e2e3,如果失败则停止,如果全部成功,则会将结果与f合并。您甚至可以将Alternative加入混合中:

f <$> e1 <*> (e2 <|> e3)