简体   繁体   English

使用回调的高阶文件夹功能

[英]Higher-order folder function using callbacks

I want to write a function that given a list of functions, will fold across that list, progressively passing in the result from each closure into the next one. 我想编写一个给出函数列表的函数,将遍历该列表,逐步将每个闭包的结果传递给下一个闭包。

The function signature of the functions in the list would be something like (pseudo-code): 列表中函数的函数签名类似于(伪代码):

typealias DoneClosure = (Dictionary) -> Void
typealias Middleware = (Dictionary, DoneClosure) -> Void

I would have a list of type Middleware and I want to reduce from left to right, folding across the list and passing the result of each closure into the next closure. 我会有一个类型Middleware的列表,我想从左到右缩小,折叠整个列表并将每个闭包的结果传递到下一个闭包。

let middleware1 = { acc, done in
    // do something with acc, modify it
    done(acc)
}

Each function would look similar to this, they'd modify the accumulator in some way and then pass the result to the done or next function. 每个函数看起来都与此类似,它们以某种方式修改累加器,然后将结果传递给done或next函数。

What I'm looking for is a recursive function that can fold across the list using callbacks so it can be processed async. 我正在寻找的是一个递归函数,它可以使用回调在列表中折叠,因此可以处理异步。 Can anyone help me out? 谁能帮我吗? (Language is irrelevant but JS or Swift is preferred). (语言无关紧要,但首选JS或Swift)。

// does not handle empty middlewareList
const makeFunctionChain = function (middlewareList, initalDic) {
    const length = middlewareList.length;
    let i = 0;
    let middleware;

    const next = function (localAccumulator) {
        middleware = middlewareList[i];
        i += 1;
        if (i === length) {
            // there is no next
            // pass a do-nothing function 
            middleware(localAccumulator, function() {});
        } else {
            middleware(localAccumulator, next);
        }
    };
    next(initalDic);
};

// usage example

const middlewareAddOnions = function (food, next) {
    // simple middleware
    food["onions"] = 3;
    next(food);
};

const middlewareAddWater = function (food, next) {
    // here we use a new accumulator
    const newFood = Object.assign({}, food, {withWater: true});
    next(newFood);
};

const middlewareCook = function (food, next) {
    // next can also be called asynchronously.
    // here we use setTimeout
    const timeToCook = 1500;
    setTimeout(function () {
        food.cooked = true;
        next(food);
    }, timeToCook);
};

const middlewareServe = function (food, next) {
    // here we read the data
    // does not use next
    if (food.cooked) {
        console.log(`Time to eat: ${JSON.stringify(food)}`);
    } else {
        console.log(`Something went wrong: ${JSON.stringify(food)}`);
    }
};


// time to try it out
const food = {
    eggs: 4,
    potatoes: 12,
    // ...
};

makeFunctionChain([
    middlewareAddOnions,
    middlewareAddWater,
    middlewareCook,
    middlewareServe
    ], food);

As noted in the comments, there is also the possibility to use Promises to have a similar result. 如评论中所述,还有可能使用Promises获得类似的结果。

I was able to figure it out using recursion (in Swift) 我能够使用递归来解决它(在Swift中)

typealias Next = (JSON) -> ()
typealias JSON = [String: Any]
typealias Middleware = (JSON, Next) -> ()

func process(middlewareList: [Middleware], value: JSON, done: @escaping Next) {
    guard !middlewareList.isEmpty else {
        done(value)
        return
    }
    let middleware = middlewareList.first!
    let slice = Array(middlewareList[1..<middlewareList.count])
    middleware(value) { json in
        process(middlewareList: slice, value: json, done: done)
    }
}

let hook1: Middleware = { json, done in
    print("hook 1")
    done(json)
}

let hook2: Middleware = { json, done in
    print("hook 2")
    var copy = json
    copy["hi"] = "hi"
    done(copy)
}

process(middlewareList: [hook1, hook2], value: [:], done: { json in
     print(json)
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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