2016-11-03 42 views
3

的里氏替换原则状态'PartialFunction extends Function`是否违反LSP?

if S is a subtype of T , then objects of type T may be replaced with objects of type S without altering any of the desirable properties of that program.

然而,在Scala中,存在PartialFunction是不适用/在所有情况下所定义。

trait Function1 { 
    def apply(x: A): R 
} 

trait PartialFunction extends Function1 { 
    def apply(x: A): R 
    def isDefinedAt(x: A): Boolean 
} 

如果应用PartialFunction为不确定的值,你会收到一个异常。

在scala中创建PartialFunction的一种简便方法是使用模式匹配。这样做,您会收到一个MatchError未定义的值。

val fn:Function1[String, Int] = s => s.length 

val pf:PartialFunction[String, Int] = { 
    case "one" => 3 
} 

def program(f:Function1[String, Int], s:String):(Boolean, Int) = (
    f.isInstanceOf[Function1[String, Int]], f(s) 
) 

program(fn, "one") == program(pf, "one") 
program(fn, "two") == program(pf, "two") 

fn: String => Int = <function1>

pf: PartialFunction[String,Int] = <function1>

program: program[](val f: String => Int,val s: String) => (Boolean, Int)

res0: Boolean = true

scala.MatchError: two (of class java.lang.String)

   at scala.PartialFunction$$anon$1.apply(delme.sc:249)

   at scala.PartialFunction$$anon$1.apply(delme.sc:247)

   at ...

两个fnpfFunction1亚型,但我不能代替通过pffn不会改变我的program。所以我认为这是对LSP的违反。

您认为如何?

+0

这将主要是一个意见件。你有关于应用或使用更一般问题的更具体问题吗? – wheaties

+0

绝对不是。我只是要求其他开发人员的建议。也许我应该将它发布到另一个社区? –

+1

你也可以定义一个'Function1',它仅仅为''one'''以外的所有输入引发异常。你违反LSP的论点是抛出一个异常可能是一个不希望的改变,但是一个'Function1'仍然可以有输入来抛出异常。例如'的BigDecimal( “ABC”)'。 'PartialFunction'和'Function1'之间的主要区别在于你有一个内置的方法来检查元素是否被首先定义。 –

回答

3

fnpf不是Function1的子类型,因为它们根本不是类型。它们是值,并且LSP没有说你可以采取T类型的任何对象并将其替换为S类型的任何对象:Int肯定是Int的子类型,但用2代替1可以使正确的程序不正确。

PartialFunction[String, Int]Function1[String, Int]一个亚型,但Function1合同不会抛出异常禁止apply,事实上明确允许:

Apply the body of this function to the argument. It may throw an exception.

所以,如果你的程序可以处理Function1[A, B]类型的对象,它必须处理apply以某种方式抛出异常,而PartialFunction抛出MatchError只是一个特例。

0

根据维基百科,还有一个额外的条款需要LSP来应用。

No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.

所以(假设维基百科是正确的),没有PartialFunction不违反LSP,因为它并不适用于这种情况。

编辑:有一个在scaladoc附加信息:(Scaladoc Function1

Note that Function1 does not define a total function, as might be suggested by the existence of PartialFunction. The only distinction between Function1 and PartialFunction is that the latter can specify inputs which it will not handle.

所以想这将是PF的另一种方式是不是FN的子类型。

FN:字符串=>诠释

PF:响应字符串=>诠释

进一步编辑的子集来评论: 不,我争辩说,LSP完全不适用。对于申请S的LSP,不得抛出新的异常。 S在这里确实会抛出新的异常,所以LSP不会被违反,因为它不适用。

+0

但是'PartialFunction'会抛出'Function'没有的'scala.MatchError'吗?或者你是否认为'Function'可以抛出任何东西?当然,这里的例外并没有真正表达出来,所以它也可能是。 – Bergi

+0

我已经放了更多的东西。我对类型理论的基础知识是不存在的,所以我非常愿意完全错误。 –

+0

啊,我明白你的引用是因为这种异常行为被*侵犯的LSP,而不是根本不适用。 – Bergi