ADTによる機能的再帰


First to Key! First to the EGG!


時々、私は機能的な思考は、Ready Player Oneの銃のように多くのように感じる!毎日、あなたはきれいで純粋な何かをする方法についての新しい手掛かりを見つけます.
私は今日のハイパーキャッシュサービスでバグに遭遇しました.私たちのクライアントの1つはバグを報告しました.Listdocsの機能は、マッチングパターンに基づいてREDISアダプターを使用して、一致するドキュメントのすべてを返していませんでした.
Redis Scanコマンドは、そのパターンにマッチしたすべてのキーを返すキーセットにマッチパターンを適用するために使用されていました.APIをブロックするのを防ぐために、あなたが望むならば、より多くを得るために、20とカーソルのカウントを返します.カーソルが0でない値であり、カーソルが次のセットを取得し、カーソルが0になるまでイテレータを続けます.このリストは完了しました.
最初の解決策は、控えめなループでしたが、少なくとも言うには、ループの間は避ける傾向があります.しかし、私は修正を必要とします.
let list = []

    async function asyncScan(cursor) {
      return new Promise((resolve, reject) => {
        client.scan(cursor, "MATCH", store + '_' + pattern, (e, r) => {
          if (e) { return reject(e) }
          resolve(r)
        })
      })
    }

    // get initial list  
    let [cursor, keys] = await asyncScan(0)
    list = list.concat(keys)

    let done = false

    while (!done) {
      // if cursor === 0 exit
      if (cursor === '0') {
        done = true
        break;
      }
      // else get more keys
      [cursor, keys] = await asyncScan(cursor)
      // add the keys then check
      list = list.concat(keys)
    }
最大の解決策ではなく、それはトリックをした!ああ!

我々は、機能的にこれを行うことができますか?

With recursion, we can iterate through a list by having the function call itself if it needs more, then when it is at the end return the result which will return through rest of the list. But how can this work in a lazy way?


再帰は強力な概念です、そして、非同期ADTのチェーン機能を利用しましょう
const matcher = `${store}_${pattern}`
return scan(0, "MATCH", matcher)
  .chain(getKeys(scan, matcher))

...

function getKeys(scan, matcher) {
  return function repeat([cursor, keys]) {
    return cursor === '0'
      ? Async.Resolved(keys)
      : scan(cursor, "MATCH", matcher)
          .chain(repeat)
          .map(v => keys.concat(v))
  }
}
より良い!
クロージャを使用して、Matcherにアクセスでき、繰り返し関数を作成して、Asyncとの怠惰な再帰を作成します.チェーン.非同期.チェーンは、ADTの現在の値を関数として返します.それから、ADTは現在のADTを連鎖関数から返されたADTと置き換えます.このADTを再帰関数でラップすることによって、キーのすべてが見つかるまで、私たちはそれ自体を呼び出し続けることができます.次に、マップ関数を使用してキーを追加し、戻り値を使用してキーを入力します.
あなたはどう思いますか.

概要
ADTを使用するだけではなく、コードの行を保存することはできません我々のコードを読みやすくし、拡張し、簡単に時間をかけて管理するために簡単にします.ADTを使用すると、学習曲線のビットですが、一度マップ、チェーンを理解し始めると、多くのタスクが宣言的かつ効率的になります.どこから始めるかわからない?https://github.com/MostlyAdequate/mostly-adequate-guide .