-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
86 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,89 @@ | ||
{% | ||
laika.title = "`parsley.implicits`" | ||
laika.excludeFromNavigation = true | ||
%} | ||
# Synactic Extensions (`parsley.implicits`) | ||
The `parsley.implicits` package contains several modules that enable new "syntax" | ||
on parsers or other values. There are currently four such modules: | ||
|
||
* `parsley.implicits.character`: contains conversions that allow for character | ||
and string literals to serve as parsers. | ||
* `parsley.implicits.combinator`: contains an implicit function that allows any | ||
parser to drop its result when required by the type of another combinator. | ||
* `parsley.implicits.lift`: enables the `lift` method on functions to allow them | ||
to work on parsers. | ||
* `parsley.implicits.zipped`: enables the `zipped` method on tuples of parsers to | ||
sequence and combine their results with a single function. | ||
|
||
## Implicit Conversions | ||
The `charLift` and `stringLift` conversions in `parsley.implicits.character` | ||
allow for Scala character and string literals to work directly as parsers for | ||
those specific literals. For example: | ||
|
||
```scala mdoc:to-string | ||
import parsley.implicits.character._ | ||
|
||
val p = 'a' ~> "bc" | ||
p.parse("abc") | ||
p.parse("axy") | ||
``` | ||
|
||
In the above, `'a': Parsley[Char]`, and `"bc": Parsley[String]`. | ||
|
||
@:callout(error) | ||
If you see an error like this, when you otherwise have the implicit imported: | ||
|
||
```scala mdoc:nest:invisible | ||
import parsley.token.Lexer | ||
import parsley.token.descriptions.LexicalDesc | ||
val lexer = new Lexer(LexicalDesc.plain) | ||
|
||
import lexer.lexeme.symbol.implicits._ | ||
``` | ||
|
||
```scala mdoc:fail | ||
val p = "cb" <~ 'a' | ||
p.parse("cba") | ||
``` | ||
|
||
Then this likely means that you have *another* conversion in scope and the | ||
ambiguity is not resolved. If the arguments reversed, this will become more | ||
evident: | ||
|
||
```scala mdoc:fail | ||
val p = 'a' ~> "bc" | ||
p.parse("abc") | ||
``` | ||
|
||
In this case, a `lexer.lexeme.symbol.implicits` is imported and is clashing. | ||
@:@ | ||
|
||
## Improved Sequencing | ||
Both the `lift` and `zipped` modules within `parsley.implicits` enable new | ||
ways of sequencing parsers in an idiomatic way. The `lift` syntax is perhaps | ||
more natural, where the function to apply appears to the left of the arguments: | ||
|
||
```scala mdoc:to-string | ||
import parsley.character.char | ||
import parsley.implicits.lift._ | ||
|
||
val add = (x: Int, y: Int) => x + y | ||
add.lift(char('a').as(5), char('b').as(6)).parse("ab") | ||
``` | ||
|
||
However, while `lift` works well when the function has its type fully elaborated, | ||
it does not infer well: | ||
|
||
```scala mdoc:fail | ||
(_ + _).lift(char('a').as(5), char('b').as(6)).parse("ab") | ||
``` | ||
|
||
This is where `zipped` comes in: by placing the function to the right of its | ||
arguments, it can infer the type of the function based on the arguments. This | ||
may appear slightly less natural, however: | ||
|
||
```scala mdoc:to-string | ||
import parsley.implicits.zipped._ | ||
(char('a').as(5), char('b').as(6)).zipped(_ + _).parse("ab") | ||
``` | ||
|
||
Both `lift` and `zipped` work for up to 22-argument functions. |