Skip to content

Commit ae6607f

Browse files
committed
Initial Commit
0 parents  commit ae6607f

File tree

11 files changed

+264
-0
lines changed

11 files changed

+264
-0
lines changed

composer.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"require": {
3+
"php": ">=5.3.0"
4+
},
5+
"autoload": {
6+
"psr-0": {
7+
"MonadPHP": "lib"
8+
}
9+
}
10+
}

lib/MonadPHP/Identity.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class Identity extends Monad {
6+
7+
}

lib/MonadPHP/ListMonad.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class ListMonad extends Monad {
6+
7+
public function unit($value) {
8+
if (!is_array($value) && !$value instanceof \Traversible) {
9+
throw new \InvalidArgumentException('Must be traversible');
10+
}
11+
return parent::unit($value);
12+
}
13+
14+
public function bind($function){
15+
return $this->unit(array_map($function, $this->value));
16+
}
17+
18+
}

lib/MonadPHP/Maybe.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class Maybe extends Monad {
6+
7+
public function bind($function){
8+
if (!is_null($this->value)) {
9+
return parent::bind($function);
10+
}
11+
return null;
12+
}
13+
14+
}

lib/MonadPHP/Monad.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
abstract class Monad {
6+
7+
protected $value;
8+
9+
public function __construct($value) {
10+
$this->value = $value;
11+
}
12+
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+
24+
public function unit($value) {
25+
$class = get_class($this);
26+
return new $class($value);
27+
}
28+
29+
public function bind($function, array $args = array()) {
30+
array_unshift($args, $this->value);
31+
return call_user_func_array($function, $args);
32+
}
33+
34+
}

lib/MonadPHP/Promise.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class Promise extends Monad {
6+
7+
protected $isResolved = false;
8+
protected $succeed = null;
9+
10+
protected $children = array();
11+
protected $success;
12+
protected $failure;
13+
14+
public function __construct($success = null, $failure = null) {
15+
$this->success = $success;
16+
$this->failure = $failure;
17+
}
18+
19+
public function unit($success = null, $failure = null) {
20+
return new static($success, $failure);
21+
}
22+
23+
public function bind($success, $failure) {
24+
$obj = $this->unit($success, $failure);
25+
if ($this->isResolved) {
26+
if ($this->succeed) {
27+
$obj->succeed($this->value);
28+
} else {
29+
$obj->fail($this->value);
30+
}
31+
} else {
32+
$this->children[] = $obj;
33+
}
34+
return $obj;
35+
}
36+
37+
public function succeed($value) {
38+
$this->resolve(true, $value);
39+
}
40+
41+
public function fail($value) {
42+
$this->resolve(false, $value);
43+
}
44+
45+
protected function resolve($status, $value) {
46+
if ($this->isResolved) {
47+
throw new \BadMethodCallException('Promise already resolved');
48+
}
49+
$this->value = $value;
50+
$this->isResolved = true;
51+
$this->succeed = $status;
52+
$callback = $status ? $this->success : $this->failure;
53+
if ($callback) {
54+
call_user_func($callback, $value);
55+
}
56+
$method = $status ? 'succeed' : 'fail';
57+
foreach ($this->children as $child) {
58+
$child->$method($value);
59+
}
60+
}
61+
62+
public function when($success = null, $failure = null) {
63+
return $this->bind($success, $failure);
64+
}
65+
}

phpunit.xml.dist

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="true"
3+
backupStaticAttributes="true"
4+
bootstrap="./vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
forceCoversAnnotation="false"
10+
mapTestClassNameToCoveredClassName="false"
11+
processIsolation="false"
12+
stopOnError="false"
13+
stopOnFailure="false"
14+
stopOnIncomplete="false"
15+
stopOnSkipped="false"
16+
testSuiteLoaderClass="PHPUnit_Runner_StandardTestSuiteLoader"
17+
strict="true"
18+
verbose="false">
19+
<testsuites>
20+
<testsuite name="Unit">
21+
<directory>./test/</directory>
22+
</testsuite>
23+
</testsuites>
24+
<filter>
25+
<whitelist>
26+
<directory suffix=".php">./lib/</directory>
27+
</whitelist>
28+
</filter>
29+
</phpunit>

test.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
require_once 'vendor/autoload.php';
4+
5+
$list = new MonadPHP\ListMonad(array(1, 2, 3, null, 4));
6+
7+
$list->lift('strval', 'strval');
8+
9+
$list->double = function($val) use ($list) {
10+
return $val * 2;
11+
};
12+
13+
$list->maybe = function($val) {
14+
return new MonadPHP\Maybe($val);
15+
};
16+
var_dump($list->maybe());
17+
var_dump($list->maybe()->double());
18+

test/MonadPHP/IdentityTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class IdentityTest extends \PHPUnit_Framework_TestCase {
6+
7+
public function testBind() {
8+
$monad = new Identity(1);
9+
$this->assertEquals(1, $monad->bind('intval'));
10+
$this->assertEquals($monad->unit(1), $monad->lift('intval'));
11+
}
12+
13+
public function testBindUnit() {
14+
$monad = new Identity(1);
15+
$this->assertEquals($monad, $monad->bind($monad->unit));
16+
}
17+
18+
}

test/MonadPHP/MaybeTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace MonadPHP;
4+
5+
class MaybeTest extends \PHPUnit_Framework_TestCase {
6+
7+
public function testBind() {
8+
$monad = new Maybe(1);
9+
$this->assertEquals("1", $monad->bind("strval"));
10+
11+
$monad2 = $monad->unit(null);
12+
$called = false;
13+
$func = function($a) use (&$called) {
14+
$called = true;
15+
};
16+
$this->assertEquals(null, $monad2->bind($func));
17+
$this->assertFalse($called);
18+
}
19+
20+
}

0 commit comments

Comments
 (0)