Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/vendor/
.php_cs.cache
.cache/
composer.lock
12 changes: 6 additions & 6 deletions .php_cs → .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?php
$finder = PhpCsFixer\Finder::create()
$finder = (new PhpCsFixer\Finder())
->exclude('vendor')
->in(__DIR__);
return PhpCsFixer\Config::create()
return (new PhpCsFixer\Config())
->setUsingCache(true)
->setCacheFile('.cache/php-cs-fixer/php-cs-fixer.cache')
->setRules([
'@PSR2' => true,
'encoding' => true,
Expand All @@ -14,7 +15,7 @@
'indentation_type' => true,
'blank_line_after_namespace' => true,
'line_ending' => true,
'lowercase_constants' => true,
'constant_case' => ['case' => 'lower'],
'lowercase_keywords' => true,
'no_closing_tag' => true,
'single_line_after_imports' => true,
Expand All @@ -23,16 +24,15 @@
'whitespace_after_comma_in_array' => true,
'blank_line_after_opening_tag' => true,
'no_empty_statement' => true,
'no_extra_consecutive_blank_lines' => true,
'no_extra_blank_lines' => true,
'function_typehint_space' => true,
'no_leading_namespace_whitespace' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'phpdoc_scalar' => true,
'phpdoc_types' => true,
'no_leading_import_slash' => true,
'no_extra_consecutive_blank_lines' => ['use'],
'blank_line_before_return' => true,
'blank_line_before_statement' => ['statements' => ['return']],
'self_accessor' => false,
'no_short_bool_cast' => true,
'no_trailing_comma_in_singleline_array' => true,
Expand Down
12 changes: 8 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
"php": ">=7.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2",
"phpunit/phpunit": "^5",
"giorgiosironi/eris": "^0.9"
"friendsofphp/php-cs-fixer": "^3.65",
"phpunit/phpunit": "^10.0",
"giorgiosironi/eris": "^1.0",
"phpstan/phpstan": "^2.0",
"vimeo/psalm": "^5.26"
},
"prefer-stable": true,
"autoload": {
Expand All @@ -29,6 +31,8 @@
"scripts": {
"test": "phpunit --no-coverage",
"fix-code": "php-cs-fixer fix --allow-risky=yes",
"check-code": "php-cs-fixer fix --verbose --diff --dry-run --allow-risky=yes"
"check-code": "php-cs-fixer fix --verbose --diff --dry-run --allow-risky=yes",
"phpstan": "phpstan analyse",
"psalm": "psalm"
}
}
31 changes: 31 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
parameters:
ignoreErrors:
-
message: '#^Unable to resolve the template type b in call to function FunctionalPHP\\FantasyLand\\applicator$#'
identifier: argument.templateType
count: 1
path: src/FantasyLand/Helpful/ApplicativeLaws.php

-
message: '#^Variable \$ap in PHPDoc tag @var does not match assigned variable \$applicatorX\.$#'
identifier: varTag.differentVariable
count: 1
path: src/FantasyLand/Helpful/ApplicativeLaws.php

-
message: '#^Parameter \#1 \$f of function FunctionalPHP\\FantasyLand\\compose expects callable\(FunctionalPHP\\FantasyLand\\Functor\<b\>\)\: FunctionalPHP\\FantasyLand\\Functor\<c\>, \(callable\(FunctionalPHP\\FantasyLand\\Functor\<b\>\)\: FunctionalPHP\\FantasyLand\\Functor\<c\>\)\|FunctionalPHP\\FantasyLand\\Functor\<c\> given\.$#'
identifier: argument.type
count: 1
path: src/FantasyLand/Helpful/FunctorLaws.php

-
message: '#^Parameter \#2 \$g of function FunctionalPHP\\FantasyLand\\compose expects callable\(FunctionalPHP\\FantasyLand\\Functor\<a\>\)\: FunctionalPHP\\FantasyLand\\Functor\<b\>, \(callable\(FunctionalPHP\\FantasyLand\\Functor\<a\>\)\: FunctionalPHP\\FantasyLand\\Functor\<b\>\)\|FunctionalPHP\\FantasyLand\\Functor\<b\> given\.$#'
identifier: argument.type
count: 1
path: src/FantasyLand/Helpful/FunctorLaws.php

-
message: '#^Parameter \#4 \$f of static method FunctionalPHP\\FantasyLand\\Helpful\\MonadLaws\:\:test\(\) expects callable\(mixed\)\: FunctionalPHP\\FantasyLand\\Monad\<b\>, callable\(a\)\: FunctionalPHP\\FantasyLand\\Useful\\Identity\<b\> given\.$#'
identifier: argument.type
count: 1
path: src/FantasyLand/Helpful/Tests/MonadLawsTest.php
8 changes: 8 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
includes:
- phpstan-baseline.neon

parameters:
level: 10
tmpDir: .cache/phpstan
paths:
- src
27 changes: 15 additions & 12 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd">
<testsuites>
<testsuite name="FantasyLand/Helpful/Tests">
<directory>./src/FantasyLand/Helpful/Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
cacheDirectory=".cache/phpunit"
>
<testsuites>
<testsuite name="FantasyLand/Helpful/Tests">
<directory>./src/FantasyLand/Helpful/Tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">./src/</directory>
</include>
</source>
</phpunit>
9 changes: 9 additions & 0 deletions psalm.baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.26.1@d747f6500b38ac4f7dfc5edbcae6e4b637d7add0">
<file src="src/FantasyLand/Helpful/FunctorLaws.php">
<PossiblyInvalidArgument>
<code><![CDATA[map($f)]]></code>
<code><![CDATA[map($g)]]></code>
</PossiblyInvalidArgument>
</file>
</files>
47 changes: 47 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0"?>
<psalm
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
cacheDirectory=".cache/psalm"
findUnusedBaselineEntry="true"
findUnusedCode="false"
errorBaseline="psalm.baseline.xml"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<!-- This is a stylistic preference from Psalm that we don't adhere to -->
<ParamNameMismatch errorLevel="suppress" />
<!--
This issue _may_ point to a valid issue, but more likely it's a
mismatch between what is possible to express in PHPDoc and what
the actual expectation is.

For example, if you have a `Maybe` monad, it will implement the
`bind` method with a more specific type than the `Monad` interface;
it will be `Maybe` instead of `Monad`. This is as expected, but
Psalm will complain about it because Psalm is assuming that a class
which implements an interface should always be subsitutable for any
other class which implements the same interface.

Ideally, that should be solvable with static parameter types and
static return types, but that doesn't seem to work as expected in
Psalm.
-->
<MoreSpecificImplementedParamType errorLevel="info" />
<!--
This issue is usually to do with extending a PHPUnit test class, so
usually a false positive. We should still report it, but at a lower
level so that we know to investigate all such instances.
-->
<PropertyNotSetInConstructor errorLevel="info" />
<!-- Psalm is complaining about being unable to load an internal PHPUnit class -->
<MissingDependency errorLevel="info" />
</issueHandlers>
</psalm>
4 changes: 2 additions & 2 deletions src/FantasyLand/Applicative.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

/**
* @template a
* @template-extends Apply<a>
* @template-extends Pointed<a>
* @extends Apply<a>
* @extends Pointed<a>
*/
interface Applicative extends
Apply,
Expand Down
2 changes: 1 addition & 1 deletion src/FantasyLand/Apply.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

/**
* @template a
* @template-extends Functor<a>
* @extends Functor<a>
*/
interface Apply extends Functor
{
Expand Down
5 changes: 2 additions & 3 deletions src/FantasyLand/Chain.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@

/**
* @template a
* @template-extends Apply<a>
* @extends Apply<a>
*/
interface Chain extends Apply
{
/**
* bind :: Monad m => (a -> m b) -> m b
*
* @template b
* @template f of callable(a): Chain<b>
*
* @param f $function
* @param callable(a): Chain<b> $function
*
* @return Chain<b>
*/
Expand Down
5 changes: 2 additions & 3 deletions src/FantasyLand/Foldable.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ interface Foldable
* reduce :: (b -> a -> b) -> b -> b
*
* @template b
* @template f of callable(b, a): b
*
* @param f $function Binary function ($accumulator, $value)
* @param b $accumulator Value to witch reduce
* @param callable(b, a): b $function Binary function ($accumulator, $value)
* @param b $accumulator Value to witch reduce
*
* @return b Same type as $accumulator
*/
Expand Down
5 changes: 2 additions & 3 deletions src/FantasyLand/Functor.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ interface Functor
* map :: Functor f => (a -> b) -> f b
*
* @template b
* @template f of callable(a): b
*
* @param f $function
* @param callable(a): b $function
*
* @return Functor<b>
*/
public function map(callable $function): Functor;
public function map(callable $function);
}
29 changes: 18 additions & 11 deletions src/FantasyLand/Helpful/ApplicativeLaws.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,28 @@ class ApplicativeLaws
/**
* Generic test to verify if a type obey the applicative laws.
*
* @param callable $assertEqual Asserting function (Applicative $a1, Applicative $a2, $message)
* @param callable $pure Applicative "constructor"
* @param Applicative $u Applicative f => f (a -> b)
* @param Applicative $v Applicative f => f (a -> b)
* @param Applicative $w Applicative f => f (a -> b)
* @param callable $f (a -> b)
* @param mixed $x Value to put into a applicative
* @template a
* @template b
* @template c
* @template d
*
* @param callable $assertEqual Asserting function (Applicative $a1, Applicative $a2, $message)
* @param a $x Value to put into a applicative
* @param callable(mixed): Applicative<mixed> $pure Applicative "constructor"
* @param Applicative<callable(a): b> $u Applicative f => f (a -> b)
* @param Applicative<callable(b): c> $v Applicative f => f (a -> b)
* @param Applicative<callable(c): d> $w Applicative f => f (a -> b)
* @param callable(a): b $f (a -> b)
*/
public static function test(
callable $assertEqual,
$x,
callable $pure,
Applicative $u,
Applicative $v,
Applicative $w,
callable $f,
$x
) {
callable $f
): void {
// identity: pure id <*> v = v
$assertEqual(
$pure(identity)->ap($v),
Expand All @@ -47,9 +52,11 @@ public static function test(
);

// interchange: u <*> pure x = pure ($ x) <*> u
/** @var callable(callable(a): b): b $ap */
$applicatorX = applicator($x);
$assertEqual(
$u->ap($pure($x)),
$pure(applicator($x))->ap($u),
$pure($applicatorX)->ap($u),
'interchange'
);

Expand Down
26 changes: 19 additions & 7 deletions src/FantasyLand/Helpful/FunctorLaws.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace FunctionalPHP\FantasyLand\Helpful;

use FunctionalPHP\FantasyLand\Functor;
use const FunctionalPHP\FantasyLand\identity;
use function FunctionalPHP\FantasyLand\compose;
use function FunctionalPHP\FantasyLand\map;

Expand All @@ -14,20 +13,33 @@ class FunctorLaws
/**
* Generic test to verify if a type obey the functor laws.
*
* @param callable $assertEqual Asserting function (Functor $f1, Functor $f2, $message)
* @param callable $f (a -> b)
* @param callable $g (a -> b)
* @param Functor $x f a
* @template a
* @template b
* @template c
*
* @param callable $assertEqual Asserting function (Functor $f1, Functor $f2, $message)
* @param callable(b): c $f (a -> b)
* @param callable(a): b $g (a -> b)
* @param Functor<a> $x f a
*/
public static function test(
callable $assertEqual,
callable $f,
callable $g,
Functor $x
) {
): void {
$identity =
/**
* @param a $x
* @return a
*/
static function ($x) {
return $x;
};

// identity: fmap id == id
$assertEqual(
map(identity, $x),
map($identity, $x),
$x,
'identity'
);
Expand Down
Loading