简体   繁体   中英

How about a higher-order function called struggle?

imagine your wife asks you to go buy some Campion flowers. as it's a rare kind of flower you're not sure if you can find it the flower shop next door. so you'll have to check every single flower shop in the town and ask for them campions. But the fact is some of the flower shops have public phone numbers and you can ask them on the phone. some of them have websites and some of them you have to walk inside.

So you start your quest from the easiest possible solutions. the point is you check every single flower shop in a unique way, as the way you talk to them or the path you walk to get to the guy. these are several functions if we talk code-wise; one function per shop.

So in the programming world, you'll have to write 10 different query function for 10 possible solutions. The next move is to try every possible solution in the list one by one and as soon as you get a positive answer/reply/return, you'll stop the quest and present the answer.

I thought it's a routine, like filter and map and reducers most likely, and i believe i'm right enough.

So how about having something like this?

in erlang:

-export([struggle/2]).

struggle(Input, Solutions) ->
    struggle(Input, Solutions, false).

struggle(_, [], false) ->
    false;
struggle(Input, [Solution|OtherSolutions], false) ->
    struggle(Input, OtherSolutions, Solution(Input));
struggle(_, _, Answer) ->
    Answer.

or in javascript:

function struggle(input, solutions)
{
    let strgl = (input, solutions, acc) => {
        if (solutions.length === 0 && acc === undefined) return undefined;
        if (acc === undefined) return strgl(input, solutions.slice(1), solutions[0](input));
        return acc;
    };
    return strgl(input, solutions, undefined);
}

don't you think it's general enough to be a built-in higher-order function?

PS: the code is working fine and there's no need to fix it. the question is, why isn't it a built-in function?

What is the exact problem?

strugle(Input, Solutions) ->
  lists:any(fun(X) -> X(Input) end, Solutions).

It is Erlang essentials. Or if you wish to return first non-false value.

strugle(Input, Solutions) ->
  any_non_false(fun(X) -> X(Input) end, Solutions).

any_non_false(F, L) ->
  try lists:any(fun(X) ->
      case F(X) of
        false -> false;
        Y -> throw({return, Y})
      end
    end, L)
  catch {return, X} -> X end.

This sounds very much like Array.prototype.find , except that your desired return value is the first truthy value that find sees, and not the element that produced the truthy value.

You could use Array.prototype.reduce to accomplish this:

function struggle(input, solutions) {
  return solutions.reduce((ans, solution) =>
    ans !== undefined ? ans : solution(input)
  , undefined);
}

Written imperatively, this would be like:

function struggle(input, solutions) {
  for (const solution of solutions) {
    const ans = solution(input);
    if (ans !== undefined) {
      return ans;
    }
  }
  return undefined;
}

This doesn't sound like it needs to be a built-in function, because it's not general enough. There's two steps here: (1) mapping the solutions, and (2) testing if the value is acceptable. Built-in JavaScript functions tend to be extremely general purpose. More specific functions are a better fit for utility libraries.

In Scheme you could write your code this way:

// some from SRFI-1, also called ormap in some dialects
(define (struggle input solutions)
  (some (lambda (f) (f input)) solutions))

It seems JavaScript got Array.prototype.some and Erlang has lists:any/2 but both are flawed by that they don't return the truthy value but only true so you only get to know if it found an answer and not what the answer was.

In JS it's simple to make a version of some that works the same as Scheme. I'm not sure about Erlang.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM