77use Widmogrod \Common ;
88use Widmogrod \FantasyLand ;
99use Widmogrod \Functional as f ;
10+ use function Widmogrod \Functional \constt ;
11+ use const Widmogrod \Functional \noop ;
1012
1113class ListtCons implements Listt, \IteratorAggregate
1214{
@@ -39,7 +41,16 @@ public function getIterator()
3941 {
4042 $ tail = $ this ;
4143 do {
42- [$ head , $ tail ] = $ tail ->headTail ();
44+ $ result = $ tail ->lazyHeadTail (function ($ x , Listt $ xs ): array {
45+ return [$ x , $ xs ];
46+ }, noop);
47+
48+ if (!is_array ($ result )) {
49+ return ;
50+ }
51+
52+ [$ head , $ tail ] = $ result ;
53+
4354 yield $ head ;
4455 } while ($ tail instanceof self);
4556 }
@@ -50,9 +61,9 @@ public function getIterator()
5061 public function map (callable $ transformation ): FantasyLand \Functor
5162 {
5263 return new self (function () use ($ transformation ) {
53- [ $ head , $ tail ] = $ this -> headTail ();
54-
55- return [ $ transformation ( $ head ), $ tail -> map ( $ transformation )] ;
64+ return $ this -> lazyHeadTail ( function ( $ x , Listt $ xs ) use ( $ transformation ) {
65+ return [ $ transformation ( $ x ), $ xs -> map ( $ transformation )];
66+ }, constt ( self :: mempty ())) ;
5667 });
5768 }
5869
@@ -148,9 +159,9 @@ public function concat(FantasyLand\Semigroup $value): FantasyLand\Semigroup
148159
149160 if ($ value instanceof self) {
150161 return new self (function () use ($ value ) {
151- [ $ x , $ xs] = $ this -> headTail ();
152-
153- return [ $ x , $ xs -> concat ( $ value )] ;
162+ return $ this -> lazyHeadTail ( function ( $ x , Listt $ xs) use ( $ value ) {
163+ return [ $ x , $ xs -> concat ( $ value )];
164+ }, constt ( self :: mempty ())) ;
154165 });
155166 }
156167
@@ -162,7 +173,7 @@ public function concat(FantasyLand\Semigroup $value): FantasyLand\Semigroup
162173 */
163174 public function equals ($ other ): bool
164175 {
165- return $ other instanceof self
176+ return $ other instanceof Listt
166177 ? $ this ->extract () === $ other ->extract ()
167178 : false ;
168179 }
@@ -172,23 +183,37 @@ public function equals($other): bool
172183 */
173184 public function head ()
174185 {
175- [$ head ] = $ this ->headTail ();
176-
177- return $ head ;
186+ return $ this ->lazyHeadTail (function ($ head ) {
187+ return $ head ;
188+ }, function () {
189+ throw new EmptyListError (__FUNCTION__ );
190+ });
178191 }
179192
180193 /**
181194 * @inheritdoc
182195 */
183196 public function tail (): Listt
184197 {
185- [$ head , $ tail ] = $ this ->headTail ();
186-
187- return $ tail ;
198+ return $ this ->lazyHeadTail (function ($ head , $ tail ) {
199+ return $ tail ;
200+ }, function () {
201+ throw new EmptyListError (__FUNCTION__ );
202+ });
188203 }
189204
190- public function headTail (): array
205+ private function lazyHeadTail ( callable $ headTail , callable $ nil )
191206 {
192- return call_user_func ($ this ->next );
207+ $ result = $ this ;
208+
209+ do {
210+ $ result = call_user_func ($ result ->next );
211+ } while ($ result instanceof self);
212+
213+ if ($ result instanceof ListtNil) {
214+ return $ nil ();
215+ }
216+
217+ return $ headTail (...$ result );
193218 }
194219}
0 commit comments