Объедините несколько общих типов в хакланг
Я пытаюсь реализовать функцию снижения от подчеркивания в хаке. Подчеркивание, функция приведения имеет следующее поведение:
Если никакая памятка не передается при первоначальном вызове Reduce, итератор не вызывается в первом элементе списка. Вместо этого первый элемент передается в качестве памятки при вызове итерируемого следующего элемента в списке.
Моя попытка реализовать функцию:
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 ответ
Я отмечаю, что линия
$memo = $iterable->firstValue();
присваивает значение типа T
в $memo
, Это кажется неправильным; $memo
дано быть типа ?Tresult
в объявлении, и присваивается значение типа Tresult
Вот:
$memo = $fn($memo, $value);
Можете ли вы объяснить, почему $memo
присваивается значение типа T
в первую очередь? Откуда ты это знаешь T
а также Tresult
подобные? Я не вижу никаких доказательств того, что эти два типа всегда должны быть одним и тем же. Проверка типов выдает здесь ошибку, потому что эта программа не безопасна; если T - это животное, а Tresult - это фрукт, а кто-то раздает нулевой фрукт, то нет способа вывести фрукт из последовательности.
Кроме того, я нахожу странным, что 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());
}
Там, теперь у нас есть две разные формы снижения, и обе они безопасны.