daveross / functional-programming-utils
PHP 5.4+ 的函数式编程工具
Requires
- php: >=5.6.0
Requires (Dev)
- phpunit/phpunit: ~5.0.0
- squizlabs/php_codesniffer: 2.*
This package is not auto-updated.
Last update: 2024-09-11 23:13:43 UTC
README
PHP 5.4+ 的函数式编程工具
目录
安装
使用 composer
在您的 composer.json
文件中添加 functional-programming-utils
的 require 语句,然后运行 composer install
或 php composer.phar install
{ "require": { "daveross/functional-programming-utils": "~4.0" } }
手动安装
包括 src
目录中的所有文件,或根据需要包括单个文件
<?php include 'path/to/functional-programming-utils/src/compose.php'; include 'path/to/functional-programming-utils/src/curry.php'; include 'path/to/functional-programming-utils/src/math.php'; include 'path/to/functional-programming-utils/src/memoize.php'; include 'path/to/functional-programming-utils/src/prop.php'; include 'path/to/functional-programming-utils/src/Monads/Monad.php'; include 'path/to/functional-programming-utils/src/Monads/Just.php'; include 'path/to/functional-programming-utils/src/Monads/Maybe.php'; include 'path/to/functional-programming-utils/src/Monads/Either.php'; include 'path/to/functional-programming-utils/src/Monads/Left.php'; include 'path/to/functional-programming-utils/src/Monads/Right.php';
许可证
查看 为什么我贡献开源软件.
贡献
欢迎提交拉取请求。单元测试受到鼓励但不是必需的。
进一步阅读和建议观看
- Professor Frisby 的《函数式编程指南》
- PHP 中的函数式编程
- Learn You a Haskell for Great Good 了解一个专为函数式编程构建的语言是如何工作的
Simon Holywell 在 2014 年 2 月 PHP Hampshire 上的 Functional PHP 演讲
PHP 5.6+ 用户注意
从 PHP 5.6 开始,您可以在文件顶部使用 use function
来引用该函数,而无需包括其整个名称,包括命名空间。我鼓励您尝试一下。
use function DaveRoss\FunctionalProgrammingUtils\add as add; $x = add( 5, 5 ); // 10
功能
数学函数
add
添加两个值
$x = DaveRoss\FunctionalProgrammingUtils\add( 5, 5 ); // 10
subtract
减去两个值
$x = DaveRoss\FunctionalProgrammingUtils\subtract( 10, 5 ); // 5
multiply
乘以两个数字
$x = DaveRoss\FunctionalProgrammingUtils\multiply( 5, 5 ); // 25
divide
除以两个数字
$x = DaveRoss\FunctionalProgrammingUtils\divide( 25, 5 ); // 5
modulus
计算除法后的余数
$x = DaveRoss\FunctionalProgrammingUtils\modulus( 13, 5 ); // 3
inverse
取反一个数字
$x = DaveRoss\FunctionalProgrammingUtils\inverse( 5 ); // -5
truthy
使用标准 PHP 规则检查值是否评估为 true
$x = DaveRoss\FunctionalProgrammingUtils\truthy( 5 ); // true $x = DaveRoss\FunctionalProgrammingUtils\truthy( 0 ); // false
true
检查值是否为布尔值 true
$x = DaveRoss\FunctionalProgrammingUtils\true( true ); // true $x = DaveRoss\FunctionalProgrammingUtils\true( 5 ); // false
falsy
使用标准 PHP 规则检查值是否评估为 false
$x = DaveRoss\FunctionalProgrammingUtils\falsy( 0 ); // true $x = DaveRoss\FunctionalProgrammingUtils\falsy( 5 ); // false
false
检查值是否为布尔值 false
$x = DaveRoss\FunctionalProgrammingUtils\false( false ); // true $x = DaveRoss\FunctionalProgrammingUtils\false( 0 ); // false
default_value
返回一个值,如果值为 null,则返回默认值
$x = DaveRoss\FunctionalProgrammingUtils\default_value( 5, 10); // 10 $x = DaveRoss\FunctionalProgrammingUtils\default_value( 5, null); // 5
属性访问
array_prop
根据相应的键从数组中返回一个值,如果键不存在于数组中,则返回 null
$a = array( 'hello' => 'world', 'a' => 'b' ); $x = DaveRoss\FunctionalProgrammingUtils\array_prop( $a, 'hello'); // 'world' $x = DaveRoss\FunctionalProgrammingUtils\array_prop( $a, 'test'); // null
object_prop
根据相应的属性名从对象中返回一个值,如果属性不存在于对象中,则返回 null
$o = new stdClass(); $o->hello = 'world'; $o->a = 'b'; $x = DaveRoss\FunctionalProgrammingUtils\object_prop( $o, 'hello'); // 'world' $x = DaveRoss\FunctionalProgrammingUtils\object_prop( $o, 'test'); // null
prop
根据适当的情况调用 array_prop
或 object_prop
$a = array( 'hello' => 'world', 'a' => 'b' ); $x = DaveRoss\FunctionalProgrammingUtils\prop( $a, 'hello'); // 'world' $x = DaveRoss\FunctionalProgrammingUtils\prop( $a, 'test'); // null $o = new stdClass(); $o->hello = 'world'; $o->a = 'b'; $x = DaveRoss\FunctionalProgrammingUtils\prop( $o, 'hello'); // 'world' $x = DaveRoss\FunctionalProgrammingUtils\prop( $o, 'test'); // null
缓存
memoize
在一个层中包装一个函数,该层存储函数针对每次调用的参数集的返回值,因此无需再次调用该函数
$f = DaveRoss\FunctionalProgrammingUtils\memoize(function($a) { return $a; }); $x = $f(5); // 5 $x = $f(5); // 5 again, but the function didn't need to be called a second time
柯里化
查看 柯里化或部分应用?部分应用和柯里化的区别 了解这些函数之间的区别。
partially_apply
部分应用 一个函数。给定一个接受多个参数的函数,返回一个已知第一个参数的函数。
$add_five = DaveRoss\FunctionalProgrammingUtils\partially_apply( 'DaveRoss\FunctionalProgrammingUtils\add', 5 ); $x = $add_five( 5 ); // 10
partially_apply_right
部分应用一个函数。给定一个接收多个参数的函数,返回一个已经知道最后一个参数的函数。
$divide_by_five = DaveRoss\FunctionalProgrammingUtils\partially_apply_right( 'DaveRoss\FunctionalProgrammingUtils\divide', 5 ); $x = $divide_by_five( 25 ); // 5
curry
柯里化一个函数。给定一个接收多个参数的函数,将其应用于一个参数,并返回一个接收下一个参数的函数,直到所有必需的参数都提供。
function add_three_integers($a, $b, $c) { return intval( $a ) + intval( $b ) + intval( $c ); } $fn = DaveRoss\FunctionalProgrammingUtils\curry( 'add_three_integers' , 1 ); $fn2 = $fn( 2 ); $x = $fn2( 3 ); // 6
组合
compose
创建一个新的函数,该函数由一系列每个函数接收一个参数的函数组成。当调用新函数时,从右到左调用这些函数,处理上一个函数的结果。
$backwards_and_uppercase = DaveRoss\FunctionalProgrammingUtils\compose( 'str_reverse', 'strtoupper' ); $x = $backwards_and_uppercase( 'dlrow olleh' ); // HELLO WORLD
单子
Monad
Monad的抽象父类。Monad是一个封装单个值并实现function map(callable $f)
的类。Monad::map()返回另一个封装函数返回值的Monad。参见Just
Monad。
Just
Just
Monad“只是”封装一个值并将函数映射到它。
$x = new Just( 5 ); $y = $x->map( function( $a ) { return $a * 5; } ); // Just(25)
Maybe
Maybe Monad识别它是否持有null
值,并在将函数映射到它时返回Maybe( null )
。否则,它像Just Monad一样行为。
$x = new Maybe( 5 ); $y = $x->map( function( $a ) { return $a * 5; } ); // Maybe(25) $a = new Maybe( null ); $b = $a->map( function( $a ) { return $a * 5; } ); // Maybe(null)
maybe函数
可以用来从Maybe Monad中提取值。
$x = new Maybe( 5 ); $y = maybe(null, function( $a ) { return $a * 5; }, $x); // 25
Either
为了实现条件语句,可以将函数定义为返回要么一个值,要么另一个值。这用Either Monad及其子类Left
和Right
来表示。
Left
Left Monad封装来自不成功函数调用的错误值。
$f = function($a) { return ( $a < 10 ) : Left::of( 'too low' ) : Right::of( $a + 1 ); } $x = $f( 15 ); // Right( 16 ) $y = $f( 5 ); // Left( "too low" )
Right
Right Monad封装成功函数调用的结果。
$f = function($a) { return ( $a < 10 ) : Left::of( 'too low' ) : Right::of( $a + 1 ); } $x = $f( 15 ); // Right( 16 ) $y = $f( 5 ); // Left( "too low" )
either函数
可以用来从Left Monad或Right Monad中提取值。
$x = Left::of( 5 ); $y = Right::of( 7 ); $left_handler = function( $a ) { return $a * 2; }; $right_handler = function( $a ) { return $a * 3; }; $a = either($left_handler, $right_handler, $x); // 10 $b = either($left_handler, $right_handler, $y); // 21