我刚刚读完一本“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/