Найти первое совпадение без повторения вызова функции и создания дополнительных переменных. Это вообще возможно? - PullRequest
1 голос
/ 19 июня 2019

Я хотел бы получить первый успешный результат из функции A, которая внутренне вызывает функции B и C по порядку.

Ключевой момент здесь - СУХОЙ.Это означает, что я не хочу вводить новую переменную (например, чтобы сохранить состояние результата предыдущего вызова функции - см. Плохой пример # 1), я не хочу повторять свое действие (например, вызывать одну и ту же функцию дважды - вижу плохопример # 2).

Пример кода на PHP, но я не зависим от PHP, любой язык приемлем.ООП, функциональный, здесь не имеет значения.

Концепции, которые я нашел до сих пор, которые могут привести к решению, - это использование Maybe (https://marcosh.github.io/post/2017/06/16/maybe-in-php.html), некоторые также предложили использовать nil (https://clojure.org/reference/data_structures#nil) в качестве типа возврата.Однако у меня пока нет достаточного рабочего примера.И мне интересно, возможно ли это решение вообще, я даже начал читать книгу под названием «Аннотированная Тьюринг», надеясь найти там некоторые ссылки на проблему или пределы ...

Плохой пример # 1 (доп.переменная):

A() {
  $B = B();
  if($B !== null) {
    return B();
  }
  return C();
}

Плохой пример # 2 (дополнительный вызов):

A() {
  if(B() !== null) {
    return B();
  }
  return C();
}

Ключевой момент здесь - СУХОЙ: - Я не хочу вводить дополнительные переменные (плохой пример #1).- Я не хочу, чтобы какая-либо функция запускалась дважды (плохой пример # 2).

Можно ли вообще написать такой код без повторения вызова и / или сохранения состояния в дополнительную переменную?

Если да - я бы хотел это увидеть.Если нет, то я хотел бы иметь действительное доказательство, которое вообще невозможно написать.

Ответы [ 2 ]

2 голосов
/ 19 июня 2019

Это для PHP 7 или выше, с использованием оператора null coalescing :

<?php
function a()
{
    return (b() ?? c());
}

function b()
{
    return null;
}

function c()
{
    return 'result from c';
}

var_dump(a());
0 голосов
/ 19 июня 2019

Я покажу примеры в JavaScript, потому что я более знаком с ним.Это будут наши функции B и C:

function B() {
    return Math.random() > 0.5 ? 'B' : null;
}

function C() {
    return 'C';
}

1.Опираясь на оценку логического or

function A() {
    return B() || C();
}

при коротком замыкании, обратите внимание, что это немного отличается от того, что вы хотите, потому что результат B() будет возвращен только в том случае, если это не ложьзначение.

2.Использование служебной функции

function firstNonNullResult(functions) {
    for (const f of functions) {
        const result = f();
        if (result !== null) {
            return result;
        }
    }
}

function A() {
    return firstNonNullResult([B, C]);
}

3.Использование ленивых вычислений

Некоторые языки, такие как Haskell, не оценивают выражения до тех пор, пока не потребуется их результат, что позволяет написать что-то вроде find isJust [B, C], где C будет оцениваться только в случае возврата Bничто.

В JavaScript или PHP вы можете добиться аналогичного эффекта, используя генераторы.

function* map(items, fn) {
    for (const item of items) {
        yield fn(item);
    }
}

function find(items, predicate) {
    for (const item of items) {
        if (predicate(item)) {
            return item;
        }
    }
}

function call(fn) {
    return fn();
}

function A() {
    return find(map([B, C], call), x => x !== null)    
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...