haskell - 如何从纯函数中调用不纯函数?

标签 haskell functional-programming

我刚刚读完一本“Learn You a Haskell for Great Good”!书,所以我的问题可能很幼稚。
我不明白的是如何从纯代码中调用“不纯”的 IO 函数。

这是一个用 C# 编写的工作示例。在我们的业务逻辑中,我们根据天气计划一些行动。我们以通常的 C# 方式进行操作。

interface IWeatherForecast
{
    WeatherData GetWeather(Location location, DateTime timestamp);
}

// concrete implementation reading weather from DB
class DbWeather : IWeatherForecast
{
    public override WeatherData GetWeather(Location location, DateTime timestamp)
    {...}
}

class WeatherFactory
{
    public IWeatherForecast GetWeatherProvider()
    {...}
}

// Business logic independent from any DB
class MaritimeRoutePlanner
{
    private IWeatherForecast weatherProvider = weatherFactory.GetWeatherProvider();

    public bool ShouldAvoidLocation(Location location, DateTime timestamp)
    {
        WeatherData weather = weatherProvider.GetWeather(location, timestamp);
        if(weather.Beaufort > 8)
            return true;
        else...
            ...
    }
}

如何在 Haskell 中实现这个逻辑?

实际上,“纯逻辑”MaritimeRoutePlanner 调用 weatherProvider.GetWeather()这是“不纯的IO”的东西。

在 Haskell 中可以吗?你会如何在 Haskell 中建模呢?

最佳答案

一般问题(如何从纯函数调用不纯函数)是一个常见问题解答。参见例如这个问题及其答案:How to return a pure value from a impure method

与软件架构相关的任何其他主题一样,如何以更实用的方式构建代码取决于具体情况。你在写什么样的程序?一个 REST API?智能手机应用程序?控制台程序?批处理作业?一个插件?

在许多情况下,你可以摆脱我所说的不纯-纯-不纯三明治:

  • 从不纯的来源收集所有必需的数据
  • 使用该数据调用纯函数
  • 用纯函数
  • 的返回值做一些不纯的事情

    在 Haskell 中你可以这样做,因为入口点总是不纯的。这是天气决策问题的简单草图。您首先定义您将处理的数据。在这里,我只包括 beaufort值,但我假设 WeatherData将包含比这更多的数据(这就是为什么我将其定义为 data 而不是 newtype )。
    data WeatherData = WeatherData { beaufort :: Int } deriving (Eq, Show)
    

    您现在可以将决策逻辑编写为纯函数:
    shouldAvoidLocation :: WeatherData -> Bool
    shouldAvoidLocation weather = beaufort weather > 8
    

    加载数据是一个完全具体的操作:
    readWeatherFromDb :: Location -> LocalTime -> IO WeatherData
    readWeatherFromDb location timestamp = -- implementation goes here...
    

    这里没有明确的抽象。该函数读取数据并返回不纯的数据。这可能是不纯-纯-不纯三明治的第一步(不纯)。

    现在可以根据该架构来构建应用程序的入口点:
    main :: IO ()
    main = do
      w <- readWeatherFromDb Berlin $ LocalTime (fromGregorian 2019 8 29) (TimeOfDay 8 55 8)
      if shouldAvoidLocation w
        then putStrLn "Avoid"
        else putStrLn "Go"
    

    调用 shouldAvoidLocation是三明治中间的纯正的好东西,然后是不纯的putStrLn来电。

    关于haskell - 如何从纯函数中调用不纯函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57703898/

    相关文章:

    java - 如何使用 Java 中结果列表本身的属性来过滤目录列表?

    javascript - 如何从回调链中删除突变?

    haskell - 如何使用未装箱的可变向量

    haskell - 一个控制鼠标的haskell程序

    Haskell 独立决定为我的数据类型推断 Bifunctor?

    function - 组合 (a -> Maybe a) 和 (an -> a) 函数

    haskell - 为什么 newtype 语法创建函数

    Python 3.3 的 yield 来自

    scala - 按特定顺序应用函数列表

    python - lambda 函数的列表或生成器在 Python 中不会返回相同的结果