I am reading the book functional programming in Scala and encounter following sentence:
If the evaluation of an expression runs forever or throws an error
instead of returning a definite value, we say that the expression does
not terminate, or that it evaluates to bottom. A function f is
strict if the expression f(x) evaluates to bottom for all x that
evaluate to bottom.
What does the sentence mean? Can someone please show me an example?
Strictness means that if an argument to a function is undefined, then the return value of the function is undefined. That's pretty much it.
The opposite is non-strictness, which means that an expression can have a value even if some of their sub-expressions are undefined.
The vast majority of programming languages are strict. However, most programming languages have at least one non-strict construct: boolean operators. For example, in Scala, this will be undefined (throw an exception):
def foo(bar: Boolean, baz: Boolean) = bar
foo(true, { throw new Exception; false })
Because foo is strict, but this won't:
true || { throw new Exception; false }
//=> res0: Boolean = true
Because || is non-strict in its second argument, which means that the return value can be defined even if some of the arguments are undefined.
Note: strict / non-strict is not the same as eager / lazy.
Related
Why does an explicit return statement (one that uses the return keyword) in an anonymous function return from the enclosing named function, and not just from the anonymous function itself?
E.g. the following program results in a type error:
def foo: String = {
((x: Integer) => return x)
"foo"
}
I know it's recommended to avoid the return keyword, but I'm interested in why the explicit and implicit return statements have a different semantics in anonymous functions.
In the following example, the return statement "survives" after m has finished executing, and the program results in a run-time exception. If anonymous functions didn't return from the enclosing function, it would not be possible to compile that code.
def main(args: Array[String]) {
m(3)
}
def m: (Integer => Unit) =
(x: Integer) => return (y: Integer) => 2
Formally speaking return is defined as always returning from the nearest enclosing named method
A return expression return e must occur inside the body of some
enclosing named method or function. The innermost enclosing named
method or function in a source program, f , must have an explicitly
declared result type, and the type of e must conform to it. The return
expression evaluates the expression e and returns its value as the
result of f . The evaluation of any statements or expressions
following the return expression is omitted.
So it doesn't have different semantics in a lambda. The wrinkle is that, unlike a normal method, a closure created from a lambda can escape a call to the enclosing method and you can get an exception if there is a return in such a closure.
If the return expression is itself part of an anonymous function, it
is possible that the enclosing instance of f has already returned
before the return expression is executed. In that case, the thrown
scala.runtime.NonLocalReturnException will not be caught, and will
propagate up the call stack.
Now, as for "why". One lesser reason is aesthetic: lambdas are expressions and it's nice when an expression and all its subexpression have the same meaning no matter what the nesting structure. Neal Gafter talks about that at http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
The main reason it exists, though, is it allows you to easily simulate forms of control flow commonly used in imperative programming but still allows you to abstract things into higher order functions. As a toy example, Java's foreach construct (for (x : xs) { yada; }) allows a return inside the loop. Scala doesn't have a language level foreach. Instead, it puts foreach in the library (not counting "for expression" without yield since they just desugar to foreach). Having a non-local return means you can take a Java foreach and translate directly to a Scala foreach.
BTW, Ruby, Smalltalk, and Common Lisp (off the top of my head) also have similar "non-local" returns.
The return keyword is reserved for (class) methods, it cannot be used in functions. You can easily test that:
object Foo {
val bar = (i: Int) => return i + i
}
This gives
<console>:42: error: return outside method definition
object Foo { val bar = (i: Int) => return i + i }
^
Mostly you can treat methods and functions as the same, because of the function's apply method behaving syntactically like calling a method, and so-called eta-expansion allowing a method to be passed as a function argument.
In this case, it makes a difference. When defining as method, it is legal:
object Foo {
def bar(i: Int): Int = return i + i
}
In summary, you should only use return in methods that allow conditional (early) returns. See this post for a discussion on methods versus functions.
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
}
Here's the error code:
Error:(32, 15) type mismatch; found : Unit required: List[(Int,
Int)]
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
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 : 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
}
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?
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).
This means that, for example, the conditional expression if (condition) consequence else differentConsequence is an expression that evaluates to a value.
For example, in this piece of code:
val foo = if (someRandomCondition) 42 else "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".
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.
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
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?
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.
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 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.
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.
So the first half of the puzzle is: the Scala Language Specification says that
if (condition) expression
is equivalent to
if (condition) expression else ()
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?
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.
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.
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.)
Why does an explicit return statement (one that uses the return keyword) in an anonymous function return from the enclosing named function, and not just from the anonymous function itself?
E.g. the following program results in a type error:
def foo: String = {
((x: Integer) => return x)
"foo"
}
I know it's recommended to avoid the return keyword, but I'm interested in why the explicit and implicit return statements have a different semantics in anonymous functions.
In the following example, the return statement "survives" after m has finished executing, and the program results in a run-time exception. If anonymous functions didn't return from the enclosing function, it would not be possible to compile that code.
def main(args: Array[String]) {
m(3)
}
def m: (Integer => Unit) =
(x: Integer) => return (y: Integer) => 2
Formally speaking return is defined as always returning from the nearest enclosing named method
A return expression return e must occur inside the body of some
enclosing named method or function. The innermost enclosing named
method or function in a source program, f , must have an explicitly
declared result type, and the type of e must conform to it. The return
expression evaluates the expression e and returns its value as the
result of f . The evaluation of any statements or expressions
following the return expression is omitted.
So it doesn't have different semantics in a lambda. The wrinkle is that, unlike a normal method, a closure created from a lambda can escape a call to the enclosing method and you can get an exception if there is a return in such a closure.
If the return expression is itself part of an anonymous function, it
is possible that the enclosing instance of f has already returned
before the return expression is executed. In that case, the thrown
scala.runtime.NonLocalReturnException will not be caught, and will
propagate up the call stack.
Now, as for "why". One lesser reason is aesthetic: lambdas are expressions and it's nice when an expression and all its subexpression have the same meaning no matter what the nesting structure. Neal Gafter talks about that at http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
The main reason it exists, though, is it allows you to easily simulate forms of control flow commonly used in imperative programming but still allows you to abstract things into higher order functions. As a toy example, Java's foreach construct (for (x : xs) { yada; }) allows a return inside the loop. Scala doesn't have a language level foreach. Instead, it puts foreach in the library (not counting "for expression" without yield since they just desugar to foreach). Having a non-local return means you can take a Java foreach and translate directly to a Scala foreach.
BTW, Ruby, Smalltalk, and Common Lisp (off the top of my head) also have similar "non-local" returns.
The return keyword is reserved for (class) methods, it cannot be used in functions. You can easily test that:
object Foo {
val bar = (i: Int) => return i + i
}
This gives
<console>:42: error: return outside method definition
object Foo { val bar = (i: Int) => return i + i }
^
Mostly you can treat methods and functions as the same, because of the function's apply method behaving syntactically like calling a method, and so-called eta-expansion allowing a method to be passed as a function argument.
In this case, it makes a difference. When defining as method, it is legal:
object Foo {
def bar(i: Int): Int = return i + i
}
In summary, you should only use return in methods that allow conditional (early) returns. See this post for a discussion on methods versus functions.
Why does an explicit return statement (one that uses the return keyword) in an anonymous function return from the enclosing named function, and not just from the anonymous function itself?
E.g. the following program results in a type error:
def foo: String = {
((x: Integer) => return x)
"foo"
}
I know it's recommended to avoid the return keyword, but I'm interested in why the explicit and implicit return statements have a different semantics in anonymous functions.
In the following example, the return statement "survives" after m has finished executing, and the program results in a run-time exception. If anonymous functions didn't return from the enclosing function, it would not be possible to compile that code.
def main(args: Array[String]) {
m(3)
}
def m: (Integer => Unit) =
(x: Integer) => return (y: Integer) => 2
Formally speaking return is defined as always returning from the nearest enclosing named method
A return expression return e must occur inside the body of some
enclosing named method or function. The innermost enclosing named
method or function in a source program, f , must have an explicitly
declared result type, and the type of e must conform to it. The return
expression evaluates the expression e and returns its value as the
result of f . The evaluation of any statements or expressions
following the return expression is omitted.
So it doesn't have different semantics in a lambda. The wrinkle is that, unlike a normal method, a closure created from a lambda can escape a call to the enclosing method and you can get an exception if there is a return in such a closure.
If the return expression is itself part of an anonymous function, it
is possible that the enclosing instance of f has already returned
before the return expression is executed. In that case, the thrown
scala.runtime.NonLocalReturnException will not be caught, and will
propagate up the call stack.
Now, as for "why". One lesser reason is aesthetic: lambdas are expressions and it's nice when an expression and all its subexpression have the same meaning no matter what the nesting structure. Neal Gafter talks about that at http://gafter.blogspot.com/2006/08/tennents-correspondence-principle-and.html
The main reason it exists, though, is it allows you to easily simulate forms of control flow commonly used in imperative programming but still allows you to abstract things into higher order functions. As a toy example, Java's foreach construct (for (x : xs) { yada; }) allows a return inside the loop. Scala doesn't have a language level foreach. Instead, it puts foreach in the library (not counting "for expression" without yield since they just desugar to foreach). Having a non-local return means you can take a Java foreach and translate directly to a Scala foreach.
BTW, Ruby, Smalltalk, and Common Lisp (off the top of my head) also have similar "non-local" returns.
The return keyword is reserved for (class) methods, it cannot be used in functions. You can easily test that:
object Foo {
val bar = (i: Int) => return i + i
}
This gives
<console>:42: error: return outside method definition
object Foo { val bar = (i: Int) => return i + i }
^
Mostly you can treat methods and functions as the same, because of the function's apply method behaving syntactically like calling a method, and so-called eta-expansion allowing a method to be passed as a function argument.
In this case, it makes a difference. When defining as method, it is legal:
object Foo {
def bar(i: Int): Int = return i + i
}
In summary, you should only use return in methods that allow conditional (early) returns. See this post for a discussion on methods versus functions.
The following two code generate different result:
def x = try{
true
} finally false
invoke x gets true
def y:Boolean = try{
return true
} finally {
return false
}
invoke y gets false
the return version behave same as Java.
Personally I never use 'return' in scala. But it's good to know how scala evaluate the value of a try-catch-finally block. Thanks.
You should not have a return statement in a finally block (even though it is technically allowed, at least in Java, C# for example forbids it).
If the Scala finally block had an implicit return, that would always clobber the intended return value. So that makes no sense.
But I suppose it cannot help you if you explicitly write it that way.
According to the Scala language spec:
A try expression try { b } finally e evaluates the block b. If evaluation of b
does not cause an exception to be thrown, the expression e is evaluated. If an exception
is thrown during evaluation of e, the evaluation of the try expression is aborted
with the thrown exception. If no exception is thrown during evaluation of e, the
result of b is returned as the result of the try expression.
This behaviour would seem to be in contradiction with that spec. I would guess that, since 'return' causes an immediate return from the function, this results in overriding the standard behaviour for a try block. An illuminating example is:
def z : Boolean = {
val foo = try { true } finally { return false }
true
}
Invoking z returns false.