@@ -32,17 +32,23 @@ public function __construct($deferred)
32
32
33
33
public function map (callable $ map ): self
34
34
{
35
- return new self (fn () => $ this ->unwrap ()->map ($ map ));
35
+ $ captured = $ this ->capture ();
36
+
37
+ return new self (static fn () => self ::detonate ($ captured )->map ($ map ));
36
38
}
37
39
38
40
public function flatMap (callable $ map ): Either
39
41
{
40
- return Either::defer (fn () => $ this ->unwrap ()->flatMap ($ map ));
42
+ $ captured = $ this ->capture ();
43
+
44
+ return Either::defer (static fn () => self ::detonate ($ captured )->flatMap ($ map ));
41
45
}
42
46
43
47
public function leftMap (callable $ map ): self
44
48
{
45
- return new self (fn () => $ this ->unwrap ()->leftMap ($ map ));
49
+ $ captured = $ this ->capture ();
50
+
51
+ return new self (static fn () => self ::detonate ($ captured )->leftMap ($ map ));
46
52
}
47
53
48
54
public function match (callable $ right , callable $ left )
@@ -52,17 +58,23 @@ public function match(callable $right, callable $left)
52
58
53
59
public function otherwise (callable $ otherwise ): Either
54
60
{
55
- return Either::defer (fn () => $ this ->unwrap ()->otherwise ($ otherwise ));
61
+ $ captured = $ this ->capture ();
62
+
63
+ return Either::defer (static fn () => self ::detonate ($ captured )->otherwise ($ otherwise ));
56
64
}
57
65
58
66
public function filter (callable $ predicate , callable $ otherwise ): Implementation
59
67
{
60
- return new self (fn () => $ this ->unwrap ()->filter ($ predicate , $ otherwise ));
68
+ $ captured = $ this ->capture ();
69
+
70
+ return new self (static fn () => self ::detonate ($ captured )->filter ($ predicate , $ otherwise ));
61
71
}
62
72
63
73
public function maybe (): Maybe
64
74
{
65
- return Maybe::defer (fn () => $ this ->unwrap ()->maybe ());
75
+ $ captured = $ this ->capture ();
76
+
77
+ return Maybe::defer (static fn () => self ::detonate ($ captured )->maybe ());
66
78
}
67
79
68
80
/**
@@ -75,12 +87,16 @@ public function memoize(): Either
75
87
76
88
public function flip (): self
77
89
{
78
- return new self (fn () => $ this ->unwrap ()->flip ());
90
+ $ captured = $ this ->capture ();
91
+
92
+ return new self (static fn () => self ::detonate ($ captured )->flip ());
79
93
}
80
94
81
95
public function eitherWay (callable $ right , callable $ left ): Either
82
96
{
83
- return Either::defer (fn () => $ this ->unwrap ()->eitherWay ($ right , $ left ));
97
+ $ captured = $ this ->capture ();
98
+
99
+ return Either::defer (static fn () => self ::detonate ($ captured )->eitherWay ($ right , $ left ));
84
100
}
85
101
86
102
/**
@@ -94,4 +110,36 @@ private function unwrap(): Either
94
110
*/
95
111
return $ this ->value ??= ($ this ->deferred )();
96
112
}
113
+
114
+ /**
115
+ * @return array{\WeakReference<self<L1, R1>>, callable(): Either<L1, R1>}
116
+ */
117
+ private function capture (): array
118
+ {
119
+ /** @psalm-suppress ImpureMethodCall */
120
+ return [
121
+ \WeakReference::create ($ this ),
122
+ $ this ->deferred ,
123
+ ];
124
+ }
125
+
126
+ /**
127
+ * @template A
128
+ * @template B
129
+ *
130
+ * @param array{\WeakReference<self<A, B>>, callable(): Either<A, B>} $captured
131
+ *
132
+ * @return Either<A, B>
133
+ */
134
+ private static function detonate (array $ captured ): Either
135
+ {
136
+ [$ ref , $ deferred ] = $ captured ;
137
+ $ self = $ ref ->get ();
138
+
139
+ if (\is_null ($ self )) {
140
+ return $ deferred ();
141
+ }
142
+
143
+ return $ self ->unwrap ();
144
+ }
97
145
}
0 commit comments