在hacklang中组合多个泛型类型

时间:2016-06-15 16:03:17

标签: hacklang

我正在尝试在hack中使用下划线实现reduce函数。在下划线中,reduce函数具有以下行为:

  

如果没有将memo传递给reduce的初始调用,则不会在列表的第一个元素上调用iteratee。相反,第一个元素作为备忘录在列表中下一个元素的iteratee调用中传递。

我尝试实现该功能:

function reduce<T, Tresult>(
  Iterable<T> $iterable,
  (function(?Tresult, T):Tresult) $fn,
  ?Tresult $memo=null):?Tresult {
    if (is_null($memo)) {
      $memo = $iterable->firstValue();
      $iterable = $iterable->skip(1);
    }

    foreach ($iterable as $value) {
      $memo = $fn($memo, $value);
    }

    return $memo;
}

这会导致错误:

Invalid return type (Typing[4110])  
  This is a value of generic type Tresult  
  It is incompatible with a value of generic type T  
    via this generic Tv

如何在T == Tresult

时告诉is_null($memo)类型检查器

1 个答案:

答案 0 :(得分:1)

我注意到了这行

$memo = $iterable->firstValue();

T类型的值指定给$memo。这似乎是错的;声明中$memo的类型为?Tresult,并在此处指定了Tresult类型的值:

$memo = $fn($memo, $value);

您能解释一下为什么$memo在第一个实例中被分配了T类型的值吗?您怎么知道TTresult是一样的?我没有看到任何证据表明这两种类型被限制为同一件事。类型检查器在这里给你一个错误,因为这个程序不是类型安全的;如果T是Animal而Tresult是Fruit,并且有人通过无效果实,则无法从序列中获得水果。

另外,我发现reduce返回可以为空的结果很奇怪;当然它应该返回给定结果类型的结果,不是吗?

如果你希望这个函数根据参数的无效性有两种不同的行为,那么为什么不只是简单地有两个函数呢?

function reduce1<T, Tresult>(
  Iterable<T> $iterable,
  (function(Tresult, T):Tresult) $fn,
  Tresult $memo): Tresult {
    foreach ($iterable as $value) {
      $memo = $fn($memo, $value);
    }
    return $memo;
}

function reduce2<T>(
  Iterable<T> $iterable,
  (function(T, T):T) $fn): T {
    return reduce1($iterable->skip(1), $fn, $iterable->firstValue());
}

在那里,我们现在有两种不同形式的reduce,它们都是类型安全的。