Skip to content

Commit 4373482

Browse files
committed
More initial work
1 parent ae6607f commit 4373482

File tree

9 files changed

+135
-41
lines changed

9 files changed

+135
-41
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
vendor

lib/MonadPHP/Chain.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class Chain extends Maybe {
6+
7+
public function __set($name, $value) {
8+
return $this->bind(function($obj) use($name, $value) {
9+
$obj->$name = $value;
10+
return $value;
11+
});
12+
}
13+
14+
public function __get($name) {
15+
return $this->bind(function($obj) use($name) {
16+
if (isset($obj->$name)) {
17+
return $obj->$name;
18+
}
19+
return null;
20+
});
21+
}
22+
23+
public function __call($name, array $args = array()) {
24+
return $this->bind(function($obj) use ($name, $args) {
25+
if (is_callable(array($obj, $name))) {
26+
return call_user_func_array(array($obj, $name), $args);
27+
}
28+
return null;
29+
});
30+
}
31+
32+
}

lib/MonadPHP/ListMonad.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,31 @@
44

55
class ListMonad extends Monad {
66

7-
public function unit($value) {
7+
public function __construct($value) {
88
if (!is_array($value) && !$value instanceof \Traversible) {
99
throw new \InvalidArgumentException('Must be traversible');
1010
}
11-
return parent::unit($value);
11+
return parent::__construct($value);
1212
}
1313

14-
public function bind($function){
15-
return $this->unit(array_map($function, $this->value));
14+
public function bind($function, array $args = array()) {
15+
$result = array();
16+
foreach ($this->value as $value) {
17+
$result[] = $this->runCallback($function, $value, $args);
18+
}
19+
return $this->unit($result);
20+
}
21+
22+
public function extract() {
23+
$ret = array();
24+
foreach ($this->value as $value) {
25+
if ($value instanceof Monad) {
26+
$ret[] = $value->extract();
27+
} else {
28+
$ret[] = $value;
29+
}
30+
}
31+
return $ret;
1632
}
1733

1834
}

lib/MonadPHP/Maybe.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ public function bind($function){
88
if (!is_null($this->value)) {
99
return parent::bind($function);
1010
}
11-
return null;
11+
return $this->unit(null);
1212
}
1313

1414
}

lib/MonadPHP/Monad.php

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,38 @@
22

33
namespace MonadPHP;
44

5-
abstract class Monad {
5+
class Monad {
66

77
protected $value;
88

99
public function __construct($value) {
1010
$this->value = $value;
1111
}
1212

13-
public function __get($name) {
14-
$name = strtolower($name);
15-
if (method_exists($this, $name)) {
16-
$cb = array($this, $name);
17-
return function() use ($cb) {
18-
return call_user_func_array($cb, func_get_args());
19-
};
20-
}
21-
return null;
22-
}
23-
2413
public function unit($value) {
14+
if ($value instanceof $this) {
15+
return $value;
16+
}
2517
$class = get_class($this);
2618
return new $class($value);
2719
}
2820

2921
public function bind($function, array $args = array()) {
30-
array_unshift($args, $this->value);
22+
return $this->unit($this->runCallback($function, $this->value, $args));
23+
}
24+
25+
public function extract() {
26+
if ($this->value instanceof self) {
27+
return $this->value->extract();
28+
}
29+
return $this->value;
30+
}
31+
32+
protected function runCallback($function, $value, array $args = array()) {
33+
if ($value instanceof self) {
34+
return $value->bind($function, $args);
35+
}
36+
array_unshift($args, $value);
3137
return call_user_func_array($function, $args);
3238
}
3339

test.php

Lines changed: 0 additions & 18 deletions
This file was deleted.

test/MonadPHP/IdentityTest.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ class IdentityTest extends \PHPUnit_Framework_TestCase {
66

77
public function testBind() {
88
$monad = new Identity(1);
9-
$this->assertEquals(1, $monad->bind('intval'));
10-
$this->assertEquals($monad->unit(1), $monad->lift('intval'));
9+
$this->assertEquals($monad->unit(1), $monad->bind('intval'));
1110
}
1211

1312
public function testBindUnit() {
1413
$monad = new Identity(1);
15-
$this->assertEquals($monad, $monad->bind($monad->unit));
14+
$this->assertEquals($monad, $monad->bind(function($value) use ($monad) { return $monad->unit($value); }));
15+
}
16+
17+
public function testExtract() {
18+
$monad = new Identity(new Maybe(1));
19+
$this->assertEquals(1, $monad->extract());
1620
}
1721

1822
}

test/MonadPHP/ListMonadTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class ListMonadTest extends \PHPUnit_Framework_TestCase {
6+
7+
public function testUnitFailure() {
8+
$this->setExpectedException('InvalidArgumentException');
9+
$monad = new ListMonad(123);
10+
}
11+
12+
public function testBindEmpty() {
13+
$monad = new ListMonad(array());
14+
$called = 0;
15+
$monad->bind(function($value) use (&$called) { $called++; return $value; });
16+
$this->assertEquals(0, $called);
17+
}
18+
19+
public function testBindNotEmpty() {
20+
$monad = new ListMonad(array(1, 2, 3));
21+
$called = 0;
22+
$new = $monad->bind(function($value) use (&$called) { $called++; return $value; });
23+
$this->assertEquals(3, $called);
24+
$this->assertEquals($monad, $new);
25+
$this->assertEquals(array(1, 2, 3), $new->extract());
26+
}
27+
28+
public function testComposedListMonad() {
29+
$monad = new ListMonad(array(1, 2, 3, null, 4));
30+
$newMonad = $monad->bind(function ($v) { return new Maybe($v); });
31+
$doubled = $newMonad->bind(function ($v) { return $v * 2; });
32+
$this->assertEquals(array(2, 4, 6, null, 8), $doubled->extract());
33+
}
34+
35+
36+
}

test/MonadPHP/MaybeTest.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,32 @@ class MaybeTest extends \PHPUnit_Framework_TestCase {
66

77
public function testBind() {
88
$monad = new Maybe(1);
9-
$this->assertEquals("1", $monad->bind("strval"));
9+
$this->assertEquals(new Maybe("1"), $monad->bind("strval"));
1010

1111
$monad2 = $monad->unit(null);
1212
$called = false;
1313
$func = function($a) use (&$called) {
1414
$called = true;
1515
};
16-
$this->assertEquals(null, $monad2->bind($func));
16+
$this->assertEquals(new Maybe(null), $monad2->bind($func));
1717
$this->assertFalse($called);
1818
}
1919

20+
public function testUnit() {
21+
$monad = new Maybe(1);
22+
$this->assertEquals($monad, $monad->unit($monad));
23+
}
24+
25+
public function testExtract() {
26+
$monad = new Maybe(1);
27+
$this->assertEquals(1, $monad->extract());
28+
}
29+
30+
public function testSelfUnit() {
31+
$monad = new Maybe(1);
32+
$m2 = $monad->unit($monad);
33+
$m3 = $monad->unit($m2);
34+
$this->assertEquals($monad, $m3);
35+
}
36+
2037
}

0 commit comments

Comments
 (0)