0

ハックでアンダースコアからreduce関数を実装しようとしています。アンダースコアでは、reduce 関数は次の動作をします。

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)

4

1 に答える 1

1

私はその行に注意してください

$memo = $iterable->firstValue();

Ttypeの値を に割り当てます$memo。これは間違っているようです。$memo?Tresult宣言で型として指定され、Tresultここで型の値が割り当てられます。

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

最初のインスタンス$memoで type の値が割り当てられる理由を説明できますか? Tどうやってそれを知っていTTresult、同じですか?これらの 2 つのタイプが同じものになるように制約されているという証拠はまったくありません。このプログラムは型安全ではないため、型チェッカーはここでエラーを出しています。T が Animal で Tresult が Fruit で、誰かが null のフルーツを渡した場合、シーケンスからフルーツを取得する方法はありません。

reduceまた、 null可能な結果を​​返すのは奇妙だと思います。確かに、指定された結果タイプの結果を返すはずですよね?

この関数に引数の nullity に応じて 2 つの異なる動作を持たせたい場合は、代わりに単純に 2 つの関数を使用しないでください。

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 には 2 つの異なる形式があり、どちらも型安全です。

于 2016-06-15T16:19:51.337 に答える