如何避免使用错误版本的数据的错误?

时间:2018-07-24 17:17:46

标签: scala functional-programming immutability monads

我正在尝试学习函数式编程禅,所以我正在使用纯函数式编程编写一个简单的编译器:Scala,在任何地方都没有'var',并且没有可变结构。

我有一个用于“已评估函数”的缓存,以加快编译速度,并在某些情况下避免无限递归。在命令式方法中,这将是对某处大型可变哈希图的引用。但是在功能方法上,它更像下面的代码(经过简化和释义,可以避免任何语法错误)。

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)

我一直都在这样做。这是我的重构后错误的主要来源。在移动代码后,我不可避免地会忘记更新其中一个“版本号”,而偶然使用了旧版本。

这是常见错误吗?如何避免呢?

我会使用do-syntax,但这使我感到更复杂。我一定在想这个错误...

1 个答案:

答案 0 :(得分:5)

这很罕见,因为每个人都在使用Statescalazcats)。 如果您使用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语法进行隐式转换的导入。