为什么没有else块会转换为函数的单元类型返回? [英] Why does the absence of an else block translate to Unit type return for a function?

查看:87
本文介绍了为什么没有else块会转换为函数的单元类型返回?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我注意到在行else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}中导致类型不匹配.因为我的if ... else if ...

I noticed there is a type mismatch caused in the line else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}. Because there is no else clause to my if ... else if ...

def euclidianDivision(dividend:Int,divisor:Int):(Int,Int)={
  val quotient = dividend/divisor
  val remainder = dividend%divisor

  (quotient,remainder)
}
def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
  def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
    val div1:Int = divisors.head
    val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
    val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
    if (divisors.tail.contains(r1)){
      firstExpansionIter(r1,divisors.tail,newAcc)
    }else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
  }
  firstExpansionIter(dividend,divisors,List((0,0))).tail
}

这是错误代码:

错误:(32,15)类型不匹配;找到:所需单位:列表[(Int, Int)] }其他if(r1 == 0 || divisors.tail.isEmpty ||!divisors.tail.contains(r1)){newAcc}

Error:(32, 15) type mismatch; found : Unit required: List[(Int, Int)] }else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}

我可以通过添加else子句来更正此问题,但是如果默认情况下未处理任何结果,该函数将尝试返回Unit怎么办?

I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?

N.B:更正的代码:

N.B : Corrected code :

def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
  def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
    val div1:Int = divisors.head
    val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
    val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
    if (divisors.tail.contains(r1)){
      firstExpansionIter(r1,divisors.tail,newAcc)
    }else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
    else throw new RuntimeException("Something unexpected happened.")
  }
  firstExpansionIter(dividend,divisors,List((0,0))).tail
}

推荐答案

我可以通过添加else子句来更正此问题,但是如果默认情况下未处理任何结果,该函数将尝试返回Unit怎么办?

I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?

在Scala中,与更多的命令式"语言不同,(几乎)所有内容都是一个表达式(很少的语句),并且每个表达式都求值为一个值(这也意味着每个方法都返回一个值).

In Scala, unlike more "imperative" languages, (almost) everything is an expression (there are very few statements), and every expression evaluates to a value (which also means that every method returns a value).

这意味着,例如,条件表达式if (condition) consequence else differentConsequence是一个求值的表达式.

This means that, for example, the conditional expression if (condition) consequence else differentConsequence is an expression that evaluates to a value.

例如,在这段代码中:

val foo = if (someRandomCondition) 42 else "Hello"

表达式的then部分将计算为42,表达式的else部分将计算为"Hello",这意味着整个if表达式将计算为42"Hello".

the then part of the expression will evaluate to 42, the else part of the expression will evaluate to "Hello", which means the if expression as a whole will evaluate to either 42 or "Hello".

那么,foo的类型将是什么?好吧,在then情况下,该值的类型为Int;在else情况下,该值的类型为String.但是,这取决于运行时值,在编译时未知.因此,作为整个 if表达式的类型,我们唯一的选择是最低的祖先(从技术上讲,

So, what is the type of foo going to be? Well, in the then case, the value is of type Int and in the else case, the value is of type String. But, this depends on the runtime value of someRandomCondition, which is unknown at compile time. So, the only choice we have as the type for the whole if expression is the lowest common ancestor (technically, the weak least upper bound) of Int and String, which is Any.

在具有联合类型的语言中,我们可以给它一个更精确的类型,即联合类型Int | String. ( Scala 3具有联合类型,因此我们可以给表达式指定此精确类型,尽管Scala 3不会推断联合类型.)在Scala 3中,我们甚至可以使用更精确的类型42 | "Hello"对其进行注释,该类型实际上是TypeScript将为等效类型推断的类型.条件表达式:

In a language with union types, we could give it a more precise type, namely the union type Int | String. (Scala 3 has union types, so we could give the expression this exact type, although Scala 3 will not infer union types.) In Scala 3, we could even annotate it with the even more precise type 42 | "Hello", which is actually the type that TypeScript is going to infer for the equivalent conditional expression:

const foo = someRandomCondition ? 42 : "Hello"

现在,让我们继续前进到问题中的代码:

Now, let's move forward towards the code in the question:

val bar = if (someRandomCondition) 42

bar的类型将是什么?上面我们说过,它是thenelse分支类型中最低的共同祖先,但是... else分支的类型是什么? else分支的评估结果是什么?

What is the type of bar going to be? We said above that it is the lowest common ancestor of the types of the then and else branch, but … what is the type of the else branch? What does the else branch evaluate to?

请记住,我们说过每个表达式的求值都是一个值,所以else分支必须求值是某个值.它不能仅仅评估为无".

Remember, we said that every expression evaluates to a value, so the else branch must evaluate to some value. It can't just evaluate to "nothing".

这可以通过单位类型的所谓单位值来解决.单位值和类型称为单位"值和类型,因为这种类型的设计使得它只能被单个值居住.单元类型没有成员,没有属性,没有字段,没有语义,没有任何内容.因此,不可能将单位类型的两个值彼此区分开或以另一种方式区分:单位类型只能有一个值,因为单位类型必须的另一个值完全相同.

This is solved by a so-called unit value of a unit type. The unit value and type are called the "unit" value and type, because the type is designed in such a way that it can only possibly be inhabited by a single value. The unit type has no members, no properties, no fields, no semantics, no nothing. As such, it is impossible to distinguish two values of the unit type from one another, or put another way: there can only be one value of the unit type, because very other value of the unit type must be identical.

在许多编程语言中,单位值和类型使用与元组值和类型相同的符号,并且可以简单地用空元组()进行标识.空元组和单位值是一回事:它们没有内容,也没有意义.例如,在Haskell中,类型和值都写为().

In many programming languages, the unit value and type use the same notation as a tuple value and type, and are simply identified with the empty tuple (). An empty tuple and a unit value are the same thing: they have no content, no meaning. In Haskell, for example, both the type and the value are written ().

Scala也有一个单位值,并且也写为().但是,单位类型为scala.Unit.

Scala also has a unit value, and it is also written (). The unit type, however, is scala.Unit.

因此,单位值是无用的值,用于表示无意义的返回值.

So, the unit value, which is a useless value, is used to signify a meaningless return value.

在某些命令性语言中,一个相关但不同的概念是void类型(或者在某些语言中,它更像是伪类型").

A related, but different concept in some imperative languages is the void type (or in some languages, it is more a "pseudo-type").

请注意,不归还"和不归还"是不同的,这将在此答案的第二部分变得很重要.

Note that "returns nothing" is different from "doesn't return", which will become important in the second part of this answer.

所以难题的前半部分是:Scala语言规范指出

So the first half of the puzzle is: the Scala Language Specification says that

if (condition) expression

等效于

if (condition) expression else ()

这意味着在(隐式)else情况下,返回类型为Unit,它与List[(Int, Int)]不兼容,因此会出现类型错误.

Which means that in the (implicit) else case, the return type is Unit, which is not compatible with List[(Int, Int)], and therefore, you get a type error.

但是为什么抛出异常可以解决此问题?

But why does throwing an exception fix this?

这使我们进入 second 特殊类型:Nothing. Nothing是所谓的底部类型,这意味着它是每种类型的子类型. Nothing 没有没有任何值.那么,Nothing的返回类型表示什么呢?

This brings us to the second special type: Nothing. Nothing is a so-called bottom type, which means that it is a subtype of every type. Nothing does not have any value. So, what then, would a return type of Nothing signify?

它表示不返回的表达式.我再说一遍:这与返回什么都不一样.

It signifies an expression that doesn't return. And I repeat what I said above: this is different from returning nothing.

仅具有副作用的方法不会返回任何内容,但是它确实会返回.它的返回类型是Unit,其返回值是().它没有有意义的返回值.
具有无限循环或引发异常的方法根本不会返回.它的返回类型为Nothing,并且它没有返回值.

A method that has only a side-effect returns nothing, but it does return. Its return type is Unit and its return value is (). It doesn't have a meaningful return value.
A method that has an infinite loop or throws an exception doesn't return at all. Its return type is Nothing and it doesn't have a return value.

这就是为什么在else子句中引发异常可以解决此问题的原因:这意味着else子句的类型为Nothing,并且由于Nothing的子类型then子句的类型到底是什么都不重要,then子句和Nothing的类型的最低公超类型将是始终then子句的类型. (考虑一下:父亲的最低共同祖先及其任何子女,孙子,曾孙等等,永远都是父亲本人.T的最低共同祖先和T的任何子类型将永远是父亲本人.由于Nothing是所有类型的子类型,因此TNothing的最低共同祖先将始终是T,因为Nothing始终是T的子类型T是.)

And that is why throwing an exception in the else clause fixes the problem: this means that the type of the else clause is Nothing, and since Nothing is a subtype of every type, it doesn't even matter what the type of the then clause is, the lowest common supertype of the type of the then clause and Nothing will always be the type of the then clause. (Think about it: the lowest common ancestor of a father and any of his children, grandchildren, great-grandchildren, etc. will always be the father himself. The lowest common ancestor of T and any subtype of T will always be T. Since Nothing is a subtype of all types, the lowest common ancestor of T and Nothing will always be T because Nothing is always a subtype of T, no matter what T is.)

这篇关于为什么没有else块会转换为函数的单元类型返回?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆