Skip to content

Commit 0b5687e

Browse files
ilario-pierbattistawidmogrod
authored andcommitted
Fixes liftM2 implementation #97 (#100)
* Fixes #97 but breaks FreeCalculatorTest.php * old liftM2 to bindM2 and correct implementation * cs fix
1 parent 20a96e5 commit 0b5687e

File tree

4 files changed

+131
-6
lines changed

4 files changed

+131
-6
lines changed

example/EitherMonadTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class EitherMonadTest extends \PHPUnit\Framework\TestCase
1919
{
2020
public function test_it_should_concat_content_of_two_files_only_when_files_exists()
2121
{
22-
$concatF = f\liftM2(function ($first, $second) {
22+
$concatF = f\bindM2(function ($first, $second) {
2323
return $first . $second;
2424
});
2525

example/FreeCalculatorTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use Widmogrod\Primitive\Stringg;
1212
use Widmogrod\Useful\PatternMatcher;
1313
use function Widmogrod\Functional\compose;
14-
use function Widmogrod\Functional\liftM2;
14+
use function Widmogrod\Functional\bindM2;
1515
use function Widmogrod\Monad\Free\foldFree;
1616
use function Widmogrod\Monad\Free\liftF;
1717
use function Widmogrod\Useful\match;
@@ -161,7 +161,7 @@ public function patternMatched(callable $fn)
161161

162162
function sum(MonadFree $a, MonadFree $b): MonadFree
163163
{
164-
return liftM2(function ($a, $b) {
164+
return bindM2(function ($a, $b) {
165165
return liftF(new Sum($a, $b, Pure::of));
166166
}, $a, $b);
167167
}
@@ -177,7 +177,7 @@ function int(int $int): MonadFree
177177

178178
function mul(MonadFree $a, MonadFree $b): MonadFree
179179
{
180-
return liftM2(function ($a, $b) {
180+
return bindM2(function ($a, $b) {
181181
return liftF(new Multiply($a, $b, Pure::of));
182182
}, $a, $b);
183183
}

src/Functional/functions.php

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
namespace Widmogrod\Functional;
66

7-
use Widmogrod\Common\ValueOfInterface;
87
use FunctionalPHP\FantasyLand\Applicative;
98
use FunctionalPHP\FantasyLand\Foldable;
109
use FunctionalPHP\FantasyLand\Functor;
1110
use FunctionalPHP\FantasyLand\Monad;
1211
use FunctionalPHP\FantasyLand\Traversable;
12+
use Widmogrod\Common\ValueOfInterface;
1313
use Widmogrod\Primitive\Listt;
1414
use Widmogrod\Primitive\ListtCons;
1515

@@ -379,7 +379,7 @@ function reThrow(\Exception $e)
379379
const liftM2 = 'Widmogrod\Functional\liftM2';
380380

381381
/**
382-
* Lift result of transformation function , called with values from two monads.
382+
* Lift result of transformation function, called with values from two monads.
383383
*
384384
* liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
385385
*
@@ -397,6 +397,39 @@ function liftM2(
397397
callable $transformation = null,
398398
Monad $ma = null,
399399
Monad $mb = null
400+
) {
401+
return curryN(
402+
3,
403+
function (
404+
callable $transformation,
405+
Monad $ma,
406+
Monad $mb
407+
) {
408+
return bindM2(function ($a, $b) use ($transformation, $mb): Monad {
409+
return $mb::of($transformation($a, $b));
410+
}, $ma, $mb);
411+
}
412+
)(...func_get_args());
413+
}
414+
415+
/**
416+
* @var callable
417+
*/
418+
const bindM2 = 'Widmogrod\Functional\bindM2';
419+
420+
/**
421+
* bindM2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m c
422+
*
423+
* @param callable $transformation
424+
* @param Monad $ma
425+
* @param Monad $mb
426+
*
427+
* @return Monad|\Closure
428+
*/
429+
function bindM2(
430+
callable $transformation = null,
431+
Monad $ma = null,
432+
Monad $mb = null
400433
) {
401434
return curryN(
402435
3,

test/Functional/LiftM2Test.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace test\Functional;
6+
7+
use FunctionalPHP\FantasyLand\Monad;
8+
use Widmogrod\Functional as f;
9+
use Widmogrod\Monad\Either;
10+
use Widmogrod\Monad\Maybe;
11+
12+
class LiftM2Test extends \PHPUnit\Framework\TestCase
13+
{
14+
/**
15+
* @dataProvider monadsProvider
16+
*/
17+
public function test_it_should_lift2M(
18+
Monad $ma,
19+
Monad $mb,
20+
callable $transformation,
21+
string $expectedFQCN,
22+
$expectedExtracted = null
23+
) {
24+
$mc = f\liftM2($transformation, $ma, $mb);
25+
26+
$this->assertInstanceOf($expectedFQCN, $mc);
27+
28+
if ($expectedExtracted !== null) {
29+
$this->assertSame($expectedExtracted, f\valueOf($mc));
30+
}
31+
}
32+
33+
public function monadsProvider()
34+
{
35+
$sumIntegers = static function (int $a, int $b) {
36+
return $a + $b;
37+
};
38+
39+
return [
40+
'maybe all nothing' => [
41+
Maybe\nothing(),
42+
Maybe\nothing(),
43+
$sumIntegers,
44+
Maybe\Nothing::class
45+
],
46+
'maybe first just' => [
47+
Maybe\just(1),
48+
Maybe\nothing(),
49+
$sumIntegers,
50+
Maybe\Nothing::class
51+
],
52+
'maybe second just' => [
53+
Maybe\nothing(),
54+
Maybe\just(2),
55+
$sumIntegers,
56+
Maybe\Nothing::class
57+
],
58+
'maybe all just' => [
59+
Maybe\just(1),
60+
Maybe\just(2),
61+
$sumIntegers,
62+
Maybe\Just::class,
63+
3
64+
],
65+
'either all left' => [
66+
Either\left('a'),
67+
Either\left('b'),
68+
$sumIntegers,
69+
Either\Left::class
70+
],
71+
'either first right' => [
72+
Either\right(3),
73+
Either\left('b'),
74+
$sumIntegers,
75+
Either\Left::class
76+
],
77+
'either second right' => [
78+
Either\left('a'),
79+
Either\right(4),
80+
$sumIntegers,
81+
Either\Left::class
82+
],
83+
'either all right' => [
84+
Either\right(3),
85+
Either\right(4),
86+
$sumIntegers,
87+
Either\Right::class,
88+
7
89+
]
90+
];
91+
}
92+
}

0 commit comments

Comments
 (0)