实现依赖于不纯 code/libraries 的纯函数式 Scala 代码时的最佳实践和方法

Best Practices and Approaches while implementing pure functional Scala code which is dependent on impure code/libraries

我目前正在实现依赖于自定义 Scala 库的业务逻辑代码,它有很多不纯的函数,我们有很多代码依赖于这个库,不能重构,因为它会影响其他人。所以我正在尝试尽可能纯粹地编写我的 scala 代码,并且需要一些用例的建议。

我有一个执行以下操作的 LDAP 实用程序库 根据用户名和密码以及returns布尔值进行认证,但是如果出现Connection异常或者找不到用户则直接抛出异常。 基于 UUID 和参数(如名字和姓氏)读取和更新数据的作用几乎相同 我的身份验证用例方法如下

  def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
    Some(ldapService.authenticate(username,password))

// or using either type to get the message as well
  def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
    (ldapService.authenticate(username,password)) match {
      case true => Right(true)
      case false => Left("Validation failed, Invalid Password")
      case exception: Exception => Left(exception.toString)
    }

//##for Some type
  authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))

//##for Either type
// Looking into how to implement

所以我想编写尽可能接近纯函数的函数式代码,需要有关如何处理此类场景以编写函数式 Scala 代码的帮助和建议。

正如 Tim 所说,在 Scala 中处理错误时,最简单的做法是将异常抛出代码包装在 Try 块中。例如:

import scala.util.{Try, Success, Failure}

Try {
  connector.makeCall()
} match {
  case Success(value) if value => Right("yay")
  case Success(value)          => Left("☹️")
  case Failure(ex)             => Left("An exception was thrown")
}

这将 return 如果 connector.makeCall() 行 returns true 为右,如果该行 returns false 则为左或异常。

这是一个人为的例子,但这是您使用它的一种方式 - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q

实际上,提供的代码不能是纯的,因为结果是 authenticateToUpdate 不仅取决于其参数(用户名、密码),还取决于 ldapService 服务。

话虽如此,我建议 authenticateToUpdate 的定义如下:

def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
  Try(ldapService(userName, password)) match {
    case Success(value) if value => Right("OK")
    case Success(_) => Right("Failed to authenticate")
    caseFailure(ex) => Left(s"Something wrong: ${ex}")
  }
}

authenticateToUpdate("user", "password"){ case (user, password) =>
 ldapService.authenticate(username,password)
}

在提供的示例中,我们只是用一个纯函数包装了一个不纯函数。