/** * Creates a new ManyMaybe instance from the given collection, * thereby composing each collection item into an Maybe monad. * * @param array $values */ protected function __construct(array $values) { $unit = function ($value) { return Maybe::unit($value); }; parent::__construct(array_map($unit, $values)); }
public function orElse(callable $f, array $args) { // Since we don't know if $f will throw an exception, we wrap the call // in a try/catch. The result wiil be Left if there's an exception. try { $maybeResult = call_user_func_array($f, $args); } catch (\Exception $e) { // Unfortunately, we lose the error context. That's just the nature // of using Maybe in a language that has exceptions. $maybeResult = Maybe::nothing(); } return $maybeResult; }
/** * Solve probeert één $goal op te lossen door regels toe te passen of * relevante vragen te stellen. Als het lukt een regel toe te passen of * een vraag te stellen geeft hij een nieuwe $state terug. Ook geeft hij * de TruthState voor $goal terug. In het geval van Maybe kan dat gebruikt * worden om af te leiden welk $goal als volgende moet worden afgeleid om * verder te komen. * * @param KnowledgeState $state huidige knowledge state * @param string goal naam van het fact dat wordt afgeleid * @return TruthState | AskedQuestion */ public function solve(KnowledgeState $state, $goal) { // Forward chain until there is nothing left to derive. $this->forwardChain($state); // Test whether the fact is already in the knowledge base and if not, if it is solely // unknown because we don't know the current goal we try to prove. Because, it could // have a variable as value which still needs to be resolved, but that might be a // different goal! $current_value = $state->value($goal); if (!($current_value instanceof Maybe && $current_value->factors == new ArrayIterator([$goal]))) { return $current_value; } // Is er misschien een regel die we kunnen toepassen $relevant_rules = new CallbackFilterIterator($state->rules->getIterator(), function ($rule) use($goal) { return $rule->infers($goal); }); // Assume that all relevant rules result in maybe's. If not, something went // horribly wrong in $this->forwardChain()! foreach ($relevant_rules as $rule) { assert('$rule->condition->evaluate($state) instanceof Maybe'); } // Is er misschien een directe vraag die we kunnen stellen? $relevant_questions = new CallbackFilterIterator($state->questions->getIterator(), function ($question) use($goal) { return $question->infers($goal); }); $this->log("Found %d rules and %s questions", [iterator_count($relevant_rules), iterator_count($relevant_questions)], LOG_LEVEL_VERBOSE); // If this problem can be solved by a rule, use it! if (iterator_count($relevant_rules) > 0) { return Maybe::because(new CallbackMapIterator($relevant_rules, function ($rule) use($state) { return $rule->condition->evaluate($state); })); } // If not, but when we do have a question to solve it, use that instead. if (iterator_count($relevant_questions) > 0) { $question = iterator_first($relevant_questions); // deze vraag is alleen over te slaan als er nog regels open staan om dit feit // af te leiden of als er alternatieve vragen naast deze (of eerder gestelde, // vandaar $n++) zijn. $skippable = iterator_count($relevant_questions) - 1; // haal de vraag hoe dan ook uit de mogelijk te stellen vragen. Het heeft geen zin // om hem twee keer te stellen. $state->questions->remove($question); return new AskedQuestion($question, $skippable); } // We have no idea how to solve this. No longer our problem! // (The caller should set $goal to undefined or something.) return Maybe::because(); }
/** * @param Maybe $other * @return JustList */ public function combine(Maybe $other) { return new JustList(array_merge($this->all(), $other->all())); }
/** * Apply a function to this Monad's value only if the value is not null * * @param callable $f * * @return Maybe */ public function map(callable $f) { return $this->isNothing() ? Maybe::of(null) : Maybe::of($f($this->value)); }
{ if ($value instanceof Maybe) { return $value; } return new static($value); } // Places an object into the monad if the isNothing function returns true public function bind(callable $function) { return $this->isNothing() ? $this : static::unit($function($this->container)); } public function isNothing() { return $this->container === false; } } // Object to test $vehicle = new Vehicle(1, 'golf', 'red', 12000, true, 1000); // Ruleset for type, color and mileage $type = function ($value) { return Maybe::unit($value->type == 'golf' ? $value : false); }; $color = function ($value) { return Maybe::unit($value->color == 'red' ? $value : false); }; $mileage = function ($value) { return Maybe::unit($value->mileage == 12000 ? $value : false); }; // Execution. On success an object will be returned $test = Maybe::unit($vehicle)->bind($type)->bind($color)->bind($mileage); var_dump($test->get());
/** * Creates a new None monad. */ public function __construct() { parent::__construct(null); }