【问题标题】:Converting impure function to a pure function improvements - Scala将不纯函数转换为纯函数改进 - Scala
【发布时间】:2018-08-30 19:07:38
【问题描述】:
object IO {

  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class SongService {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName

    //impure call
    val geniusStringResponse = IO.getHtmlFromWebsiteViaHttp(searchLink, apiKey)

   //Extra processing on geniusStringResponse
  }
}

我目前的设计是我将有一个服务类,负责通过外部 API 获取一些信息。现在我明白了,不可能有 100% 纯函数。

我的问题:处理需要连接到 Scala/FP 中的外部 API 的情况的最佳方法是什么?目的是通过最小化不纯函数来拥有最合适的“函数式编程风格”

目前,我将所有 API 调用封装在 IO 对象中。这够合适吗?我看到了单子的例子。在这种情况下我应该合并一个单子风格吗?

【问题讨论】:

  • “我将所有 API 调用封装在 IO 对象中” - 你的意思是,你只是把你的不纯函数移到了一个名为 "IO"object 中?我认为这有点过于简单化了......
  • 对。因此,如果这不是解决此问题的最佳方法,那该怎么做呢?
  • 我不确定这有多不纯。您只是从外部资源中获取价值。对我来说似乎是透明的。就像@AndreyTyukin 所说,将代码移动到一个单独的对象就是……移动代码。它不会(实际上)影响程序的运行。
  • 是的,但是从外部资源中获取价值的行为不是天生不纯洁的吗?不能保证输出与指定的输入相同。 (404 错误或 301 正常)
  • @Lasf 它不是引用透明的,因为它很容易由于外部状态的变化而给出不同的结果,例如您尝试访问的服务器出现故障或机器失去互联网访问权限。更不用说 API 的歌单可能会定期更新。

标签: scala functional-programming pure-function


【解决方案1】:

这不是一个 FP 问题,因为我没有看到你的代码在 FP 方面有任何问题,但是在我看来你应该做的是使用依赖注入,这样,为了测试,你可以用一个测试类替换IO,它有保证的响应。像这样的:

abstract class IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String
}

class IOImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = {
    Http(link)
      .param("access_token", apiKey)
      .asString
      .body
  }
}

class IOTestImpl extends IO {
  def getHtmlFromWebsiteViaHttp(link: String, apiKey: String = ""): String = ??? //some test HTML
}

然后为您服务:

class SongService(io: IO) {
  private def retrieveSongId(songName: String): Option[JsValue] = {
    val formattedSongName = songName.replace(" ", "%20")
    val searchLink = "https://api.genius.com/search?q=" + formattedSongName
    val geniusStringResponse = io.getHtmlFromWebsiteViaHttp(searchLink, apiKey)
   //Extra processing on geniusStringResponse
  }
}

然后,当您实例化您的 SongService 时,在测试中传递 IOTestImpl,否则传递 IOImpl。您可能会在dependency injectiondatabase access objects 上找到一些相关信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-18
    • 2020-06-07
    • 2020-01-06
    • 2017-06-28
    • 1970-01-01
    • 2021-08-08
    • 2014-04-19
    • 2019-10-05
    相关资源
    最近更新 更多