Skip to content

Commit d03636f

Browse files
committed
README Recursion
1 parent 5e90296 commit d03636f

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

README.md

+42-2
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,48 @@ will return `Right [true, false, true]`.
105105
Starting with v9.0.0, all parsers and combinators in this package are always
106106
stack-safe.
107107

108+
## Recursion
109+
110+
For the most part, we can just write recursive parsers (parsers defined in
111+
terms of themselves) and they will work as we expect.
112+
113+
In some cases like this:
114+
115+
```purescript
116+
aye :: Parser String Char
117+
aye = do
118+
char 'a'
119+
aye
120+
```
121+
122+
we might get a compile-time *CycleInDeclaration* error which looks like this:
123+
124+
```
125+
The value of aye is undefined here, so this reference is not allowed.
126+
127+
128+
See https://github.com/purescript/documentation/blob/master/errors/CycleInDeclaration.md for more information,
129+
or to contribute content related to this error.
130+
```
131+
132+
This is happening because we tried to call `aye` recursively __“at a point
133+
where such a reference would be unavailable because of *strict evaluation*.”__
134+
135+
The
136+
[best way to solve](https://discourse.purescript.org/t/parsing-recursively-with-purescript-parsing/3184/2)
137+
this is to stick a
138+
[`Data.Lazy.defer`](https://pursuit.purescript.org/packages/purescript-lazy/docs/Data.Lazy#v:defer)
139+
in front of the parser to break the cycle.
140+
141+
```purescript
142+
aye :: Parser String Char
143+
aye = defer \_ -> do
144+
char 'a'
145+
aye
146+
```
147+
148+
149+
108150
## Resources
109151

110152
- [*Monadic Parsers at the Input Boundary* (YouTube)](https://www.youtube.com/watch?v=LLkbzt4ms6M) by James Brock is an introductory tutorial to monadic parser combinators with this package.
@@ -124,8 +166,6 @@ from a failed alternative.
124166

125167
- [*Parser Combinators in Haskell*](https://serokell.io/blog/parser-combinators-in-haskell) by Heitor Toledo Lassarote de Paula.
126168

127-
- [*Parsing recursively*](https://github.com/Thimoteus/SandScript/wiki/2.-Parsing-recursively) “Because PureScript is not evaluated lazily like Haskell is, this will bite us if we naïvely try to port recursive Haskell parsing to PureScript.”
128-
129169
There are lots of other great monadic parsing tutorials on the internet.
130170

131171
## Related Packages

test/Main.purs

+24-1
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ module Test.Main where
88
import Prelude hiding (between, when)
99

1010
import Control.Alt ((<|>))
11-
import Control.Lazy (fix)
11+
import Control.Lazy (fix, defer)
1212
import Control.Monad.State (State, lift, modify, runState)
1313
import Data.Array (some, toUnfoldable)
1414
import Data.Array as Array
1515
import Data.Bifunctor (lmap, rmap)
1616
import Data.Either (Either(..), either, fromLeft, hush)
1717
import Data.Foldable (oneOf)
1818
import Data.List (List(..), fromFoldable, (:))
19+
import Data.List as List
1920
import Data.List.NonEmpty (NonEmptyList(..), catMaybes, cons, cons')
2021
import Data.List.NonEmpty as NE
2122
import Data.Maybe (Maybe(..), fromJust, maybe)
@@ -1128,3 +1129,25 @@ main = do
11281129
, expected: [ "Expected letter at position index:6 (line:2, column:1)", "", "🍷bbbb" ]
11291130
}
11301131

1132+
log "\nTESTS recursion"
1133+
1134+
do
1135+
let
1136+
aye :: Parser String Char
1137+
aye = defer \_ -> char 'a' *> aye
1138+
assertEqual' "recusion aye"
1139+
{ actual: runParser "aaa" aye
1140+
, expected: Right 'a'
1141+
}
1142+
1143+
do
1144+
let
1145+
aye :: Parser String (List Char)
1146+
aye = defer \_ -> List.Cons <$> char 'a' <*> (aye <|> bee <|> pure List.Nil)
1147+
1148+
bee :: Parser String (List Char)
1149+
bee = defer \_ -> List.Cons <$> char 'b' <*> (aye <|> bee <|> pure List.Nil)
1150+
assertEqual' "mutual recusion aye bee"
1151+
{ actual: runParser "aabbaa" aye
1152+
, expected: Right ('a' : 'a' : 'b' : 'b' : 'a' : 'c' : List.Nil)
1153+
}

0 commit comments

Comments
 (0)