phunkie/phunkie-adt

此包最新版本(0.1.0)没有可用的许可信息。

0.1.0 2017-08-20 12:12 UTC

This package is not auto-updated.

Last update: 2024-09-15 04:19:59 UTC


README

"在计算机编程中,尤其是在函数式编程和类型理论中,代数数据类型是一种组合类型,即通过组合其他类型形成的类型。" —— 老牌的维基百科

求和类型

在计算机科学中,求和类型是一种用于存储可以取几个不同但固定的类型的值的数据结构。在任何时候只能使用其中一种类型,并且一个标签字段明确指示正在使用哪一种。

假设我们想创建一个类型 Weekday。我们希望它仅限于一周中可能的7天:星期日、星期一、星期二、星期三、星期四、星期五和星期六。

我们可以使用典型的过程式或面向对象技术以多种方式实现这一点。我们可以使用枚举,将常量分组在接口下或通过继承。

目前PHP没有枚举,所以这不是一个选择。

在接口中分组常量是一种流行的替代方案,但它不提供任何类型安全性。

<?php
interface WeekDay {
    const SUNDAY = 'Sunday',
          MONDAY = 'Monday',
          TUESDAY = 'Tuesday',
          WEDNESDAY = 'Wednesday',
          THURSDAY = 'Thursday',
          FRIDAY = 'Friday',
          SATURDAY = 'Saturday';
}

当将星期几传递给函数时,我不能指定Weekday类型作为类型提示。

最后,我们可以尝试扩展超类或实现公共接口。

<?php
interface Weekday {}
final class Sunday implements Weekday { }
final class Monday implements Weekday { }
//...

现在我们可以为传递的Weekday类型提供类型提示

<?php
function orderPizza(Weekday $weekday, Pizza $pizza)
{
    switch (get_class($weekday)) {
        case Wednesday::class : return new WednesdayPromotionOrder($pizza);
        default : return new Order($pizza);
    }
}

然而,在PHP中没有方法可以保证接口不会被扩展到与库一起分发的那些之外。没有任何东西可以阻止冥王星粉丝这样做

<?php
final class Plutoday implements Weekday { }

突然之间,我们可以现在以奇怪的日子订购披萨。但别担心!求和类型就在那里,可以拯救我们免于这种疯狂。

首先,我们创建一个类型构造函数 Weekday。PHP中创建可提示类型的唯一方法是使用类。所以,让我们使用它。

<?php
abstract class Weekday implements TypeConstructor { use SumType; }

然后我们将其密封。让我们在同时使用 ImmutableSealed 来添加不可变性

<?php
abstract class Weekday extends ImmutableSealed implements TypeConstructor { use SumType; }

ImmutableSealed 要求我们告诉类型构造函数可以创建哪些类型

<?php
abstract class Weekday extends ImmutableSealed implements TypeConstructor, SumTypeTag {
    const sealedTo = [ Sunday::class, Monday::class, Tuesday::class,
        Wednesday::class, Thursday::class, Friday::class, Saturday::class];
    public function __construct() { $this->applySeal(); }
}

我们仍然需要创建求和类型

<?php
final class Sunday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
final class Monday extends Weekday { use SumType; const typeConstructor = Weekday::class; }
//...
final class Saturday extends Weekday { use SumType; const typeConstructor = Weekday::class; }

如果我们试图在密封之外扩展 Weekday,我们将得到一个类型错误。

<?php
final class Plotoday extends Weekday { use SumType; const typeConstructor = Weekday::class; }

new Plutoday; // results in:
              // TypeError has been thrown with message: "Weekday is sealed and cannot be extended outside seal."

待办事项

  • 详尽分析
  • 泛型/种类:一阶,高阶
  • 实现 Show, Eq, Ord

最后的话

  • Phunkie 是 alpha 软件,可能不适用于生产环境