phunkie/phunkie

PHP 函数结构库

0.11.3 2023-06-12 06:00 UTC

This package is not auto-updated.

Last update: 2024-09-14 13:54:01 UTC


README

Build Status

Phunkie 是一个为 PHP 提供函数结构的库。

为了更好地开发 Phunkie,请考虑安装 phunkie-console

$ bin/phunkie-console
Welcome to phunkie console.

Type in expressions to have them evaluated.

phunkie >

选项

phunkie > Some(1)
$var0: Option<Int> = Some(1)

phunkie > None()
$var1: None = None

phunkie > Option(42)
$var2: Option<Int> = Some(42)

phunkie > Option(null)
$var3: None = None

不可变列表

您可以使用 :import 命令导入 phunkie 模块。使用 :help 获取更多信息

phunkie > ImmList(2,3,4)
$var0: List<Int> = List(2, 3, 4)

phunkie > ImmList(Some(1), None(), Some(3))
$var1: List<Int> = List(Some(1), None, Some(3))

phunkie > :import immlist/*
imported function \Phunkie\Functions\immlist\head()
imported function \Phunkie\Functions\immlist\init()
imported function \Phunkie\Functions\immlist\tail()
imported function \Phunkie\Functions\immlist\last()
imported function \Phunkie\Functions\immlist\reverse()
imported function \Phunkie\Functions\immlist\length()
imported function \Phunkie\Functions\immlist\concat()
imported function \Phunkie\Functions\immlist\take()
imported function \Phunkie\Functions\immlist\drop()
imported function \Phunkie\Functions\immlist\nth()
imported function \Phunkie\Functions\immlist\filter()
imported function \Phunkie\Functions\immlist\reject()
imported function \Phunkie\Functions\immlist\reduce()

phunkie > head (ImmList(1,2,3))
$var2: Int = 1

phunkie > tail (ImmList(1,2,3))
$var3: List<Int> = List(2, 3)

phunkie > init (ImmList(1,2,3))
$var4: List<Int> = List(1, 2)

phunkie > last (ImmList(1,2,3))
$var5: Int = 3

phunkie > reverse (ImmList(1,2,3))
$var6: List<Int> = List(3, 2, 1)

phunkie > length (ImmList(1,2,3))
$var7: Int = 3

phunkie > ImmList("Black", "Red", "Green")->filter(function($x) { return $x != "Green"; })
$var8: List<String> = List("Black", "Red")

phunkie > ImmList("Black", "Red", "Green")->partition(function($x) { return $x != "Green"; })
$var9: (List<String>, List<String>) = Pair(List("Black", "Red"), List("Green"))

phunkie > ImmList("A","B","C")->zip(ImmList(1,2,3))
$var10: List<(String, Int)> = List(Pair("A", 1), Pair("B", 2), Pair("C", 3))

不可变集合和不可变映射

phunkie > ImmSet(1,2,3)
$var0: Set<Int> = Set(1, 2, 3)

phunkie > ImmSet(1,2,3,2) // No duplicates
$var1: Set<Int> = Set(1, 2, 3)

phunkie > ImmSet(1,2,3)->contains(3)
$var2: Boolean = true

phunkie > ImmSet(1,2,3)->minus(3) // creates a new set
$var3: Set<Int> = Set(1, 2)

phunkie > ImmSet(1,2,3)->plus(4) // again, new set
$var4: Set<Int> = Set(1, 2, 3, 4)

phunkie > ImmMap(["hello" => "there"])
$var5: Map<String, String> = Map("hello" -> "there")

phunkie > ImmMap(["hello" => "there"])->get("hello")
$var6: Option<String> = Some("there")

phunkie > ImmMap(["hello" => "there"])->get("zoom")
$var7: None = None

phunkie > ImmMap(["hello" => "there"])->plus("hi", "here") // creates a new Map
$var8: Map<String, String> = Map("hello" -> "there", "hi" -> "here")

phunkie > class Id {
phunkie {     private $number;
phunkie {     public function __construct($n)
phunkie {     {
phunkie {         $this->number = $n;
phunkie {     }
phunkie { }
defined class Id

phunkie > ImmMap(
phunkie (   new Id(1), "John Smith",
phunkie (   new Id(2), "Chuck Norris",
phunkie (   new Id(3), "Jack Bauer"
phunkie ( )
$var9: Map<Id, String> = Map(Id@2d05ca0 -> "John Smith", Id@2d05ca1 -> "Chuck Norris", Id@2d05ca2 -> "Jack Bauer")

Function1

phunkie > $f = Function1('strlen')
$f : Function1 = Function1(?=>?)

phunkie > $f("hello");
$var0: Int = 5

phunkie > $g = Function1(function($x) { return $x % 2 === 0; })
$g : Function1 = Function1(?=>?)

phunkie > $g($f("hello"))
$var1: Boolean = false

phunkie > $h = $g->compose($f)
$h : Function1 = Function1(?=>?)

phunkie > $h("hello")
$var2: Boolean = false

phunkie > $h = $f->andThen($g)
$h : Function1 = Function1(?=>?)

phunkie > $h("hello")
$var3: Boolean = false

Functor

phunkie > Some(1)->map(function($x) { return $x + 1;})
$var0: Option<Int> = Some(2)

phunkie > None()->map(function($x) { return $x + 1;})
$var1: None = None

phunkie > ImmList(1,2,3)->map(function($x) { return $x + 1;})
$var2: List<Int> = List(2, 3, 4)

phunkie > ImmList(1,2,3)->zipWith(function($x) { return $x + 1;})
$var3: List<(Int, Int)> = List(Pair(1, 2), Pair(2, 3), Pair(3, 4))

phunkie> :import functor/*
Imported function \Phunkie\Functions\functor\fmap()

phunkie > fmap (function($x) { return $x + 1;}, Some(42))
$var4: Option<Int> = Some(43)

Foldable

phunkie > ImmList(1,2,3)->foldLeft(0)(function($x, $y) { return $x + $y; })
$var0: Int = 6

phunkie > ImmList("a", "b", "c")->foldLeft("letters:")(function($x, $y) { return $x . $y; })
$var1: String = "letters:abc"

phunkie > ImmList("a", "b", "c")->foldRight("<--")(function($x, $y) { return $x . $y; })
$var2: String = "abc<--"

Currying

phunkie > $curried = ImmList(1,2,3)->foldLeft(0)(_)
$curried : Callable = <function>

phunkie > $curried(function($x, $y) { return $x + $y; })
$var0: Int = 6

phunkie > $implode = curry('implode')
$implode: Callable = <function>

phunkie > $implodeColon = $implode(":")
$implodeColon: Callable = <function>

phunkie > $implodeColon(["a", "b", "c"])
$var1: String = "a:b:c"

phunkie> :import immlist/take
Imported function \Phunkie\Functions\immlist\take

phunkie > $take = uncurry(take)
$take: Callable = <function>

phunkie > $take(2, ImmList(1,2,3))
$var2: List<Int> = List(1, 2)

Functor Composite

phunkie > $fa = Functor(Option)
$fa : Phunkie\Cats\Functor\FunctorComposite = Functor(Option)

phunkie > $fa->map(Option(1), function($x) { return $x + 1; })
$var0: Option<Int> = Some(2)

phunkie > fa->map(Option(ImmList(1,2,3)), function($x) { return $x + 1; })
Notice: Object of class Phunkie\Types\ImmList could not be converted to int

phunkie > $fa = Functor(Option)->compose(ImmList)
$fa : Phunkie\Cats\Functor\FunctorComposite = Functor(Option(List))

phunkie > $fa->map(Option(ImmList(1,2,3)), function($x) { return $x + 1; })
$var1: Option<List<Int>> = Some(List(2, 3, 4))

Applicative

phunkie > None()->pure(42)
$var0: Option<Int> = Some(42)

phunkie > ImmList()->pure(42)
$var1: List<Int> = List(42)

phunkie > Some(1)->apply(Some(function($x) { return $x + 1;}))
$var2: Option<Int> = Some(2)

phunkie > None()->apply(Some(function($x) { return $x + 1;}))
$var3: None = None

phunkie > ImmList(1,2,3)->apply(ImmList(function($x) { return $x + 1;}))
$var4: List<Int> = List(2, 3, 4)

phunkie > ImmList()->apply(ImmList(function($x) { return $x + 1;}))
$var5: List<Nothing> = List()

phunkie > Some(1)->map2(Some(2), function($x, $y) { return $x + $y; })
$var6: Option<Int> = Some(3)

phunkie > ImmList(1,2,3)->map2(ImmList(4,5,6), function($x, $y) { return $x + $y; })
$var7: List<Int> = List(5, 6, 7, 6, 7, 8, 7, 8, 9)

Monad

phunkie > ImmList(1,2,3)->flatMap(function($x) { return Some($x + 1); })
$var0: List<Int> = List(2, 3, 4)

phunkie > ImmList(1,2,3)->flatMap(function($x) { return $x % 2 === 0 ? None() : Some($x + 1); })
$var1: List<Int> = List(2, 4)

phunkie > ImmList(1,2,3)->flatMap(function($x) { return None(); })
$var2: List<Nothing> = List()

phunkie > ImmList(1,2,3)->flatMap(function($x) { return ImmList($x + 1, $x + 2); })
$var3: List<Int> = List(2, 3, 3, 4, 4, 5)

phunkie > Some(1)->flatMap(function($x) { return Some($x + 1); })
$var4: Option<Int> = Some(2)

phunkie > Some(1)->flatMap(function($x) { return None(); })
$var5: None = None

phunkie > None()->flatMap(function($x) { return Some(42); })
$var6: None = None

phunkie > ImmList(1,2,3)->flatMap(function($x) { return ImmList(Some($x + 1)); })
$var7: List<Option<Int>> = List(Some(2),Some(3),Some(4))

phunkie > Some(Some(42))->flatten()
$var8: Option<Int> = Some(42)

phunkie > ImmList(ImmList(1,2,3))->flatten()
$var9: List<Int> = List(1, 2, 3)

Kleisli

phunkie > $f = kleisli(function($x) { return Some($x + 1); })
$f: Phunkie\Cats\Kleisli = Phunkie\Cats\Kleisli@7b902640

phunkie > $g = kleisli(function($x) { return Some($x + 4); })
$g: Phunkie\Cats\Kleisli = Phunkie\Cats\Kleisli@7b902629

phunkie > $x = $f->andThen($g)
$x: Phunkie\Cats\Kleisli = Phunkie\Cats\Kleisli@7b902792

phunkie > $x->run(3)
$var0: Option<Int> = Some(8)

Monoid

phunkie > :import semigroup/*
Imported function \Phunkie\Functions\semigroup\combine()
Imported function \Phunkie\Functions\semigroup\zero()

phunkie > combine(1,1)
$var0: Int = 2

phunkie > combine("a","b")
$var1: String = "ab"

phunkie > combine([1,2,3], [4,5,6])
$var2: Array<Int> = [1, 2, 3, 4, 5, 6]

phunkie > combine(true, false)
$var3: Boolean = false

phunkie > combine(ImmList(1,2,3), ImmList(4,5,6))
$var4: List<Int> = List(1, 2, 3, 4, 5, 6)

phunkie > combine(Some(4), Some(2))
$var5: Option<Int> = Some(6)

phunkie > combine(Some("4"), Some("2"))
$var6: Option<String> = Some("42")

phunkie > ImmList(1,2,3)->combine(ImmList(4,5,6)
$var7: List<Int> = List(1, 2, 3, 4, 5, 6)

phunkie > zero(Option(42))
$var8: None = None

phunkie > Option(42)->zero()
$var9: None = None

phunkie > ImmList(1,2,3)->zero()
$var10: List<Nothing> = List()

phunkie > zero(rand(1,45))
$var11: Int = 0

phunkie > zero([1,2,3])
$var12: Array<Nothing> = []

模式匹配

处理列表

<?php
use Phunkie\Types\ImmList;
use function Phunkie\PatternMatching\Referenced\ListWithTail;
use function Phunkie\PatternMatching\Referenced\ListNoTail;

function sum(ImmList $list): int { $on = pmatch($list); switch(true) {
    case $on(Nil): return 0;
    case $on(ListNoTail($x, Nil)): return $x;
    case $on(ListWithTail($x, $xs)): return $x + sum($xs);}
}

验证 Mondads 通配符

<?php

$boom = function () { return Failure(Nel(new \Exception("Boom!"))); };
$on = pmatch($boom()); switch (true) {
    case $on(Success(_)): return 2; break;
    case $on(Failure(_)): return 10; break;
}

$yay = function () { return Success("yay!"); };
$on = pmatch($yay()); switch (true) {
    case $on(Failure(_)): return 2; break;
    case $on(Success(_)): return 10; break;
}

Option 通配符

<?php

$on = pmatch(None()); switch (true) {
    case $on(None): return 10; break;
    case $on(Some(_)): return 2; break;
}

透镜

phunkie > :import lens/*
imported function \Phunkie\Functions\lens\trivial()
imported function \Phunkie\Functions\lens\self()
imported function \Phunkie\Functions\lens\fst()
imported function \Phunkie\Functions\lens\snd()
imported function \Phunkie\Functions\lens\contains()
imported function \Phunkie\Functions\lens\member()
imported function \Phunkie\Functions\lens\makelenses()

phunkie > trivial()->get(42) // returns Unit which does not print anything

phunkie > trivial()->set(42,34)
$var0: Int = 34

phunkie > self()->get(42)
$var1: Int = 42

phunkie > self()->set(42,34)
$var2: Int = 42

phunkie > fst()->get(Pair(1,2))
$var3: Int = 1

phunkie > fst()->set(3, Pair(1,2))
$var4: (Int, Int) = Pair(3, 2)

phunkie > snd()->get(Pair(1,2))
$var5: Int = 2

phunkie > snd()->set(3, Pair(1,2))
$var6: (Int, Int) = Pair(1, 3)

phunkie > $s = ImmSet(1,2,3)
$s : ImmSet<Int> = Set(1, 2, 3)

phunkie > contains(2)->get($s)
$var7: Boolean = true

phunkie > contains(4)->set($s, true)
$var8: ImmSet<Int> = Set(1, 2, 3, 4)

phunkie > contains(3)->set($s, false)
$var9: ImmSet<Int> = Set(1, 2)

phunkie > $m = ImmMap(["a" => 1, "b" => 2])
$m : ImmMap<String, Int> = Map("a" -> 1, "b" -> 2)

phunkie > member("b")->get($m)
$var10: Option<Int> = Some(2)

phunkie > member("b")->set($m, None())
$var11: ImmMap<String, Int> = Map("a" -> 1)

phunkie > member("b")->set($m, Some(3))
$var12: ImmMap<String, Int> = Map("a" -> 1, "b" -> 3)

for 推导

<?php

function letter($x)
{
    return Option($x);
}

function uppercase($x)
{
    return Option(strtoupper($x));
}

function quote($x)
{
    return Option('"' . $x . '"');
}

for_                            (__
    ($l  ) ->_ (letter('x'))    ,__
    ($u  ) ->_ (uppercase($l))  ,__
    ($res) ->_ (quote($u))      )
-> yields ($res);

// The above is the equivalent of:

$res = letter('x')->flatMap(function($l) {
    return uppercase($l)->flatMap(function($u) {
        return quote($u)->map(function($res) {
            return $res;
        });
    });
});

如果右侧返回一个元组,它可以被分配给两个单独的变量

<?php

$x = for_ (__
  ($left, $right) ->_ (Some(Pair("left", "right")))
) -> yields ($right);

// $x == "right"

您可以使用 $_ 忽略返回值

<?php

$x = for_ (__
  ($_, $right) ->_ (Some(Pair("left", "right")))
) -> yields ($right);

// $x == "right"