|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Relaxed Lambda Syntax" |
| 4 | +nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/relaxed-lambdas.html |
| 5 | +--- |
| 6 | + |
| 7 | +# Relaxed Lambda Syntax |
| 8 | + |
| 9 | +This experimental addition combines several small improvements to write function literals in more flexible ways. These improvements are specified in |
| 10 | +[SIP 74](https://github.com/scala/improvement-proposals/pull/113) and |
| 11 | +[SIP 75](https://github.com/scala/improvement-proposals/pull/118). |
| 12 | +They are enabled by the experimental language import |
| 13 | +```scala |
| 14 | +import language.experimental.relaxedLambdas |
| 15 | +``` |
| 16 | + |
| 17 | +## Single Line Lambdas |
| 18 | + |
| 19 | +Lambda expression following a `:` on the same line are now supported. Previously, |
| 20 | +we needed a newline and indent after the arrow, e.g. |
| 21 | +```scala |
| 22 | +xs.map: x => |
| 23 | + x + 1 |
| 24 | +``` |
| 25 | +We now also allow to write the lambda on a single line: |
| 26 | +```scala |
| 27 | +xs.map: x => x + 1 |
| 28 | +``` |
| 29 | +The lambda extends in this case to the end of the line. |
| 30 | + |
| 31 | +The syntax works for all kinds of function literals. They can start with one or more parameters, or with type parameters, or they can be partial functions starting |
| 32 | +with `case`. |
| 33 | + |
| 34 | +```scala |
| 35 | +Seq((1, 2), (3, 4)).map: (a, b) => a + b |
| 36 | + |
| 37 | +Seq((1, 2), (3, 4)).map: (a: Int, b: Int) => a + b |
| 38 | + |
| 39 | +Seq((1, 2), (3, 4)).collect: case (a, b) if b > 2 = a |
| 40 | + |
| 41 | +(1, true).map: [T] => (x: T) => List(x) |
| 42 | +``` |
| 43 | + |
| 44 | +The syntax does not work for function values that do not contain a `=>` or `?=>`. For instance the following are illegal. |
| 45 | + |
| 46 | +```scala |
| 47 | +Seq((1, 2), (3, 4)).map: _ + _ // error |
| 48 | + |
| 49 | +Seq(1, 2, 3).map: plus1 // error |
| 50 | +``` |
| 51 | + |
| 52 | +Single-line lambdas can be nested, as in: |
| 53 | +```scala |
| 54 | + xs.map: x => x.toString + xs.dropWhile: y => y > 0 |
| 55 | +``` |
| 56 | + |
| 57 | +### Detailed Spec |
| 58 | + |
| 59 | +A `:` means application if its is followed by one of the following: |
| 60 | + |
| 61 | + 1. a line end and an indented block, |
| 62 | + 2. a parameter section, followed by `=>` or `?=>`, a line end and an indented block, |
| 63 | + 3. a parameter section, followed by `=>` or `?=>` and an expression on a single line, |
| 64 | + 4. a case clause, representing a single-case partial function. |
| 65 | + |
| 66 | +(1) and (2) is the status quo, (3) and (4) are new. |
| 67 | + |
| 68 | +**Restriction:** (3) and (4) do not apply in code that is immediately enclosed in parentheses (without being more closely enclosed in braces or indentation). This is to avoid an ambiguity with type ascription. For instance, |
| 69 | +```scala |
| 70 | +( |
| 71 | + x: Int => Int |
| 72 | +) |
| 73 | +``` |
| 74 | +still means type ascription, no interpretation as function application is attempted. |
| 75 | + |
| 76 | +## Curried Multi-Line Lambdas |
| 77 | + |
| 78 | +Previously, we admitted only a single parameter section and an arrow before |
| 79 | +an indented block. We now also admit multiple such sections. So the following |
| 80 | +is now legal: |
| 81 | + |
| 82 | +```scala |
| 83 | +def fun(f: Int => Int => Int): Int = f(1)(2) |
| 84 | + |
| 85 | +fun: (x: Int) => y => |
| 86 | + x + y |
| 87 | +``` |
| 88 | + |
| 89 | +In the detailed spec above, point (2) is modified as follows: |
| 90 | + |
| 91 | +2. _one or more_ parameter sections, _each_ followed by `=>` or `?=>`, and finally a line end and an indented block. |
| 92 | + |
| 93 | +## Case Expressions |
| 94 | + |
| 95 | +Previously, case clauses making up a partial function had to be written in |
| 96 | +braces or an indented block. If there is only a single case clause, we now allow it to be written also inside parentheses or as a top-level expression. |
| 97 | + |
| 98 | +Examples: |
| 99 | + |
| 100 | +```scala |
| 101 | +case class Pair(x: Int, y: Int) |
| 102 | + |
| 103 | +Seq(Pair(1, 2), Pair(3, 4)).collect(case Pair(a, b) if b > 2 => a) |
| 104 | + |
| 105 | +Seq(Pair(1, 2), Pair(3, 4)).collect( |
| 106 | + case (a, b) => |
| 107 | + println(b) |
| 108 | + a |
| 109 | +) |
| 110 | + |
| 111 | +val partial: PartialFunction[(Int, Int), Int] = case (a, b) if b > 2 => a |
| 112 | +``` |
| 113 | + |
| 114 | +## Syntax Changes |
| 115 | + |
| 116 | +``` |
| 117 | +Expr ::= ... |
| 118 | + | ExprCaseClause |
| 119 | +
|
| 120 | +ColonArgument ::= colon {LambdaStart} indent (CaseClauses | Block) outdent |
| 121 | + | colon LambdaStart {LambdaStart} expr ENDlambda |
| 122 | + | colon ExprCaseClause |
| 123 | +``` |
| 124 | +Here, ENDlambda is a token synthesized at the next end of line following the |
| 125 | +token that starts the production. ` |
| 126 | + |
| 127 | +`ExprCaseClause` already exists in the grammar. It is defined as follows: |
| 128 | +``` |
| 129 | +ExprCaseClause ::= ‘case’ Pattern [Guard] ‘=>’ Expr |
| 130 | +``` |
0 commit comments