Scala 声明空模式匹配函数

Scala 声明空模式匹配函数,scala,Scala,如何声明空/无大小写模式匹配函数以满足类型定义?我很高兴函数在调用时抛出运行时异常 我正在处理,其中有一个工作函数,它对给定String=>Intmap的树表示的数学表达式执行变量替换。我想调用相同的代码路径,即使在不应该存在变量的情况下(在本例中是在对表达式求导之后),但我找不到一种简洁的方法来满足类型要求。以下是我的完整代码,它可以工作,但感觉不正确: 抽象类树 case类Sum(l:Tree,r:Tree)扩展了Tree case类Var(n:String)扩展了树 case类Const(

如何声明空/无大小写模式匹配函数以满足类型定义?我很高兴函数在调用时抛出运行时异常

我正在处理,其中有一个工作函数,它对给定
String=>Int
map的树表示的数学表达式执行变量替换。我想调用相同的代码路径,即使在不应该存在变量的情况下(在本例中是在对表达式求导之后),但我找不到一种简洁的方法来满足类型要求。以下是我的完整代码,它可以工作,但感觉不正确:

抽象类树
case类Sum(l:Tree,r:Tree)扩展了Tree
case类Var(n:String)扩展了树
case类Const(v:Int)扩展了树
对象计算器模式SPRIME{
def eval(tree:tree,env:String=>Int):Int=树匹配{
案例总和(l,r)=>评估(l,环境)+评估(r,环境)
案例变量(n)=>环境变量(n)
案例常数(v)=>v
}
def eval(tree:tree):Int=eval(tree,{case“ignore”=>-1})
def派生(tree:tree,v:String):tree=树匹配{
案例和(l,r)=>和(推导(l,v),推导(r,v))
案例变量(n)如果(n==v)=>Const(1)
大小写=>Const(0)
}
def main(参数:数组[字符串]):单位={
val env:String=>Int={case“x”=>5 case“y”=>7}
瓦尔树=总和(
总和(常数(7),变量(“y”),
总和(Var(“x”)、Var(“x”))
)
println(评估(树木、环境))
println(派生(树,“x”))
println(eval(派生(树,“x”)))
}
}
正如您所看到的,我有一个虚拟的
{case“ignore”=>-1}
来让类型系统满意,代码工作得很好,但我觉得一定有更好的方法来做到这一点。以下是我考虑过的两个备选方案:

  • 只需向
    eval(tree:tree)
    写出一个完整的方法体,而不是尝试调用
    eval(tree:tree,env:String=>Int)
    ,但这会重复处理
    Sum
    Const
    案例的代码
  • 使
    env
    成为可选/联合类型,并允许它抛出NPE

  • 这里的惯用方法是什么?

    有几种方法:

    首先,正如jwvh所指出的,您可以通过为两个参数
    eval
    中的第二个参数使用默认参数来消除单参数
    eval

    接下来的问题是,默认参数应该是什么

    env
    是一个
    String=>Int
    ,它是
    Function1[-a,+R]
    的缩写:参数类型为逆变型,结果类型为协变型。就我们的目的而言,这意味着任何接受超类型
    String
    (包括
    String
    )并导致子类型
    Int
    (包括
    Int
    )的函数都可以工作

    既然你说你可以投掷,这是一个合理的默认函数:

    { a: Any => throw new AssertionError(s"shouldn't have looked up $a in the environment") }
    
    假设系统的某些其他组件正在确保,如果在传递给
    eval
    的树中有
    Var
    表达式,则环境中总是有一个适当的条目,这可能是最诚实的做法:系统中重要的事情不是保持不变,因此,试图在你的系统中对此进行推理可能只会让事情变得更糟

    该函数之所以有效,是因为它的类型为
    Any=>Nothing
    ,它是
    String=>Int
    的子类型:您可以向它传递
    String
    String
    Any
    的子类型),并且它永远不会产生不是
    Int
    Int
    的子类型的结果(它没有结果)

    或者,您也可以使用
    PartialFunction.empty
    作为默认值,如果调用它,它将抛出
    MatchError
    。这适用于使用部分函数文字(这就是裸
    {case…}
    块)

    所以我会选择其中一个(都有
    类型Env=String=>Int

    然后将
    eval
    定义为:

    def eval(tree: Tree, env: Env = emptyEnv): Int
    
    作为旁注,我强烈建议将
    密封

    sealed abstract class Tree
    

    这限制了可以定义扩展
    树的类的位置,并为执行
    树的不变量提供了更有力的保证。

    我将删除第二个
    eval()
    ,只需给
    env
    一个默认值
    \u=>-1
    。感谢您分享这些示例!
    def eval(tree: Tree, env: Env = emptyEnv): Int
    
    sealed abstract class Tree