我已经尝试掌握 IO monad 一段时间了,这是有道理的。如果我没记错的话,目标是将副作用的描述和实际执行分开。如下例所示,Scala 有一种方法可以获取非引用透明的环境变量。出现了两个问题。
问题一:这个是参照透明的吗
问题 2:如何正确(基于单位/属性)测试这一点?不可能检查相等性,因为它将检查内存引用,并且不可能检查内部函数,因为如果我没有弄错的话,函数比较是不可能的。但是,我不想在单元测试中运行实际的副作用。另外,这是设计错误还是 IO monad 的误用?
case class EnvironmentVariableNotFoundException(message: String) extends Exception(message)
object Env {
def get(envKey: String): IO[Try[String]] = IO.unit.flatMap((_) => IO.pure(tryGetEnv(envKey)))
private[this] def tryGetEnv(envKey: String): Try[String] =
Try(System.getenv(envKey))
.flatMap(
(x) =>
if (x == null) Failure(EnvironmentVariableNotFoundException(s"$envKey environment variable does not exist"))
else Success(x)
)
}
Run Code Online (Sandbox Code Playgroud) 我一直在努力解决第5天的问题2(https://adventofcode.com/2017/day/5).它与第一个问题的不同之处在于,如果项目大于等于3,则减少而不是增加1.
当使用测试数据运行实现时,它会产生正确的结果,因此看起来实现是完美的.此外,递归调用看起来处于尾部位置,但它仍然产生stackoverflow异常.
代码看起来像这样
module AdventOfCode5 where
type Instruction = Int
type Position = Int
main :: IO ()
main = do
input <- readFile "day5input.txt"
let instructions = fmap (read :: String -> Instruction) $ lines input
_ <- putStrLn $ show $ computeResult (Prelude.length instructions) 0 (+1) $ instructions
return ()
main2 :: IO ()
main2 = do
input <- readFile "day5input.txt"
let instructions = fmap (read :: String -> Instruction) $ lines input
_ <- putStrLn …Run Code Online (Sandbox Code Playgroud)