如何避免使用错误版本数据的错误?
How do I avoid bugs where I use the wrong version of data?
我正在尝试学习函数式编程禅宗,所以我正在使用纯函数式编程编写一个简单的编译器:Scala,没有 'var' 任何地方,也没有可变结构。
我有一个 "already evaluated functions" 的缓存来加速编译并在某些情况下避免无限递归。在命令式方法中,这将是对某处大型可变哈希映射的引用。但在功能方法中,它更像是下面的代码(经过大量简化和解释,请原谅任何语法错误)。
def compileAdd(
cache0: Cache,
uncompiledLeftSubExpr: UncompiledExpr,
uncompiledRightSubExpr: UncompiledExpr)
: (Cache, CompiledExpr) = {
val (cache1, compiledLeftSubExpr) =
compileExpression(cache0, uncompiledLeftSubExpr)
val (cache2, compiledRightSubExpr) =
compileExpression(cache1, uncompiledRightSubExpr)
val newExpression =
AddExpression(compiledLeftSubExpr, compiledRightSubExpr)
(cache2, newExpression)
}
但是,想象一下如果我有一个错误,最后一行是:
(cache1, newExpression)
我一直这样做。这是我的 post-refactor 错误的主要来源;移动代码后,我不可避免地忘记更新其中一个 "version numbers",不小心使用了旧版本。
这是一个常见的错误吗?如何避免?
我会使用 do-syntax,但我觉得它更复杂 "var"。我一定是想错了...
这个不常见,因为大家都在用State
(scalaz, cats)。
如果您使用 State
-monad(例如来自上述库之一),您的示例应该看起来像这样:
def compileAdd(
uncompiledLeftSubExpr: UncompiledExpr,
uncompiledRightSubExpr: UncompiledExpr
): State[Cache, CompiledExpr] = for {
compiledLeftSubExpr <- compileExpression(uncompiledLeftSubExpr)
compiledRightSubExpr <- compileExpression(uncompiledRightSubExpr)
} yield AddExpression(compiledLeftSubExpr, compiledRightSubExpr)
或者
def compileAdd(
left: UncompiledExpr,
right: UncompiledExpr
): State[Cache, CompiledExpr] = for {
a <- compileExpression(left)
b <- compileExpression(right)
} yield AddExpression(a, b)
这假设 compileExpression
也有签名
def compileExpression(u: UncompiledExpr): State[Cache, CompiledExpr]
并且包含提供 for-yield
语法的所有具有隐式转换的导入。
我正在尝试学习函数式编程禅宗,所以我正在使用纯函数式编程编写一个简单的编译器:Scala,没有 'var' 任何地方,也没有可变结构。
我有一个 "already evaluated functions" 的缓存来加速编译并在某些情况下避免无限递归。在命令式方法中,这将是对某处大型可变哈希映射的引用。但在功能方法中,它更像是下面的代码(经过大量简化和解释,请原谅任何语法错误)。
def compileAdd(
cache0: Cache,
uncompiledLeftSubExpr: UncompiledExpr,
uncompiledRightSubExpr: UncompiledExpr)
: (Cache, CompiledExpr) = {
val (cache1, compiledLeftSubExpr) =
compileExpression(cache0, uncompiledLeftSubExpr)
val (cache2, compiledRightSubExpr) =
compileExpression(cache1, uncompiledRightSubExpr)
val newExpression =
AddExpression(compiledLeftSubExpr, compiledRightSubExpr)
(cache2, newExpression)
}
但是,想象一下如果我有一个错误,最后一行是:
(cache1, newExpression)
我一直这样做。这是我的 post-refactor 错误的主要来源;移动代码后,我不可避免地忘记更新其中一个 "version numbers",不小心使用了旧版本。
这是一个常见的错误吗?如何避免?
我会使用 do-syntax,但我觉得它更复杂 "var"。我一定是想错了...
这个不常见,因为大家都在用State
(scalaz, cats)。
如果您使用 State
-monad(例如来自上述库之一),您的示例应该看起来像这样:
def compileAdd(
uncompiledLeftSubExpr: UncompiledExpr,
uncompiledRightSubExpr: UncompiledExpr
): State[Cache, CompiledExpr] = for {
compiledLeftSubExpr <- compileExpression(uncompiledLeftSubExpr)
compiledRightSubExpr <- compileExpression(uncompiledRightSubExpr)
} yield AddExpression(compiledLeftSubExpr, compiledRightSubExpr)
或者
def compileAdd(
left: UncompiledExpr,
right: UncompiledExpr
): State[Cache, CompiledExpr] = for {
a <- compileExpression(left)
b <- compileExpression(right)
} yield AddExpression(a, b)
这假设 compileExpression
也有签名
def compileExpression(u: UncompiledExpr): State[Cache, CompiledExpr]
并且包含提供 for-yield
语法的所有具有隐式转换的导入。