Как вернуть значение из фазера CATCH блока?

Каков синтаксис для возврата значения от фазера CATCH из блока, который не является подпрограммой?

sub foo() {
    <1 2 3>.map: -> $a {
        die 'oops';
        CATCH { default { 'foo' } }
    }
}

sub bar() {
    <1 2 3>.map: -> $a {
        die 'oops';
        CATCH { default { return 'bar' } }
    }
}

say foo(); # (Nil, Nil, Nil)
say bar(); # Attempt to return outside of immediatelly-enclosing Routine (i.e. `return` execution is outside the dynamic scope of the Routine where `return` was used)

изменить: желаемый результат:

say baz(); # (baz baz baz)

Вариант использования - maping Seq с помощью метода, который периодически генерирует исключение, обрабатывая исключение в блоке, переданном в карту, путем возврата значения по умолчанию.


person J Hall    schedule 18.04.2018    source источник
comment
Я хочу say baz() вернуть '(baz baz baz)'. Сценарий использования, который я имел в виду, заключался в том, чтобы сопоставить Seq с методом, который может периодически выходить из строя, но ЛОВИТЬ это исключение и сопоставить со значением по умолчанию.   -  person J Hall    schedule 19.04.2018


Ответы (2)


Возврат выходит за пределы области действия функции, но в том, как вы его используете в bar(), задействованы две функции.

  1. Сам метод bar().
  2. Лямбда, в которую вы встроили возврат.

Это означает, что ваш возврат неоднозначен (ну, по крайней мере, для некоторых людей), и компилятор откажется.

Без «return» значение в foo() обрабатывается как константа внутри блока, и блок возвращает Nil. Это означает, что в foo() вы эффективно избегали анализа значения return, эффективно помещая Nil в стек.

Вот почему у вас есть 3 Nil в захваченных выходных данных для foo(). Для bar() неясно, хотите ли вы прекратить выполнение подпрограммы bar() при первом сгенерированном исключении или просто хотели передать 'bar' обратно как значение, отличное от Nil, которое блок CATCH поместил в стек.

Немного измененная версия вашего кода

#!/bin/env perl6

sub foo() {
    <1 2 3>.map: -> $a {
        die 'oops';
    }
    CATCH { default { 'foo' } }
}

sub bar() {
    <1 2 3>.map: -> $a {
        die 'oops';
    }
    CATCH { default { return 'bar' } }
}

say foo();

say bar();

может прояснить это. Его вывод

[edwbuck@phoenix learn_ruby]$ ./ed.p6 
Nil
bar
person Edwin Buck    schedule 18.04.2018
comment
Я думаю, что ваши аргументы в пользу того, почему ваша версия кода работает, ошибочны. Причина, по которой Nil является возвращаемым значением первого кода, заключается в том, что блоки CATCH всегда оцениваются как Nil. По этой причине возвращаемое значение функции всегда будет Nil, даже если die не происходит. Вместо этого причина, по которой CATCH вне лямбда вообще улавливает исключение, заключается в том, что результат вызова map записывается в sink контексте (он же void контекст), что приводит к немедленной оценке полного списка на предмет побочных эффектов, вызывая исключение. быть брошенным и CATCH быть запущенным. - person timotimo; 19.04.2018
comment
Я искал, как мне вернуть 'foo'x3 или' bar'x3. Вариант использования, который я пытался воспроизвести, был не всегда умирающей лямбдой, а картой, обертывающей периодически сбойный вызов, для которого я хотел бы сопоставить значение по умолчанию. Я отредактирую вопрос для этого случая. - person J Hall; 19.04.2018

Здесь происходит то, что ленивые списки делают поток управления неочевидным.

Возвращаемое значение обеих ваших функций - это Seq, значения которого генерируются путем вызова маленькой лямбды для значений a, b и c по очереди. Зная это, легко понять, почему вы не можете изменить возвращаемое значение bar: bar уже было возвращено до того, как ваша лямбда будет вызвана в первый раз. Когда список равен sayd, генерируются все значения и генерируется исключение.

Правильный способ получить то, что вы хотите, - это вызвать .eager для результата вашей карты, что приведет к оценке всего списка перед возвратом функции, что позволяет вам использовать return для изменения значения, возвращаемого bar.

person timotimo    schedule 18.04.2018