2017-01-09 4 views
0

どのようにしてエリキシル剤に遅延パターンを導入できますか?エリクサーに遅延パターンを実装する方法は?

私はそれが何であるか説明しましょう。私はいくつかのfn()が実装されるべきであるとしましょう。それ以降はn秒遅れます。しかし、私がこのfn()を2度目に呼び出すと、この関数は2回目の呼び出し後にn秒に実装されるべきです。この関数評価をすべて終了する方法もあるはずです。

Lodashの_.debounce関数を参照してください。ここ

+1

私の頭の上から離れて、あなたは単純なgenserverでそれを実装できます。たぶんシンプルな方法があります。 – JustMichael

+0

ええ、ええ、私はより単純な抽象化を探しています – asiniy

+0

プロセスを望む機能は望んでいません。 http://elixir-lang.org/getting-started/processes.htmlプロセスが現在の値をカウントダウンする間に、n - の新しい入力値も受け取ります。この値は、ローカル状態で維持されるリストに置きます。カウントダウンが完了すると、リストの次のメンバーに進み、もう一度受信しながらダウンをカウントします。 – GavinBrelstaff

答えて

-1

オーケーあなたが軌道に乗るように簡略化する場合である:ここ nをご遅延を確認するために、大きなn年代を必要としていますので、秒が、ループ・ステップでではありません。ここでは、関数を呼び出す例としてIO.putsを使用します。

defmodule myModule do 
def loop(list,count) do 
    receive do 
    n -> list = list ++ n 

    :die -> 
     Process.exit(self(), :kill)    
    end 
    if count == 0 do 
    IO.puts("timeout") 
    [head|tail] = list 
    loop(tail, head) 
    else 
    loop(list, count-1) 
    end 
end 
end 
+0

これはどのようにしてOPが要求したものですか?質問は単純な遅延ではありません。 – michalmuskala

+0

@michalmuskala各遅延タイムアウト後に関数の例としてIO.putsを呼び出します。もちろん、最初にプロセスを生成し、必要なときにn値のpidメッセージを送信する必要があります。 – GavinBrelstaff

0

状態を保存するには、プロセスが必要です。単純な関数では十分ではありません。このためのプロセスを作成すると、わずか数行のコードである:

defmodule Debounce do 
    def start_link(f, timeout) do 
    spawn_link(__MODULE__, :loop, [f, timeout]) 
    end 

    def loop(f, timeout) do 
    receive do 
     :bounce -> loop(f, timeout) 
     :exit -> :ok 
    after timeout -> 
     f.() 
    end 
    end 
end 

あなたは、このプロセス:bounceを送信することができ、それがDebounce.start_link/2で指定されたものにそのタイムアウトをリセットします。また、このプロセスを:exitに送信することもできます。機能を実行しないで終了します。

テスト:

f = Debounce.start_link(fn -> IO.inspect(:executing) end, 1000) 
IO.puts 1 
send f, :bounce 
:timer.sleep(500) 

IO.puts 2 
send f, :bounce 
:timer.sleep(500) 

IO.puts 3 
send f, :bounce 
:timer.sleep(500) 

IO.puts 4 
send f, :bounce 
:timer.sleep(2000) 

IO.puts 5 

出力:

1 
2 
3 
4 
:executing 
5 
2

非常に素朴でシンプルなソリューションは、生のプロセスを使用することができます。

defmodule Debounce do 
    def start(fun, timeout) do 
    ref = make_ref() 

    # this function is invoked when we wait for a next application 
    recur = fn recur, run -> 
     receive do 
     ^ref -> 
      # let's start counting! 
      run.(recur, run) 
     end 
    end 

    # this function is invoked when we "swallow" next applications 
    # and wait until we finally apply the function 
    run = fn recur, run -> 
     receive do 
     ^ref -> 
      # let's reset the counter 
      run.(recur, run) 
     after 
     timeout -> 
      # time is up, let's call it for real & return to waiting 
      fun.() 
      recur.(recur, run) 
     end 
    end 
    pid = spawn_link(fn -> recur.(recur, run) end) 
    fn -> send(pid, ref) end 
    end 
end 

のは

iex> f = Debounce.start(fn -> IO.puts("Hello"), 5000) 
iex> f.() 
iex> f.() 
# wait some time 
Hello 
iex> f.() # wait some time 
Hello 

例を見てみましょうしかし、これは多くの問題を抱えている - 私たちの「デバウンサ」プロセスは、効果的に永遠に住んでいる、我々は、デバウンス性と信頼性は、せいぜい、大ざっぱでキャンセルすることはできません。私たちは改善することができますが、私たちが呼び出すことができる簡単な楽しみの戻り値を失い、その代わりに私たちのデバウンサーを "適用"する特別な関数を呼び出す必要があります。

defmodule Debounce do 
    def start(fun, timeout) do 
    ref = make_ref() 

    # this function is invoked when we wait for a next application 
    recur = fn recur, run -> 
     receive do 
     {^ref, :run} -> 
      # let's start counting! 
      run.(recur, run) 
     {^ref, :cancel} -> 
      :cancelled 
     end 
    end 

    # this function is invoked when we "swallow" next applications 
    # and wait until we finally apply the function 
    run = fn recur, run -> 
     receive do 
     {^ref, :run} -> 
      # let's reset the counter 
      run.(recur, run) 
     {^ref, :cancel} -> 
      :cancelled 
     after 
     timeout -> 
      # time is up, let's call it for real & return to waiting 
      fun.() 
      recur.(recur, run) 
     end 
    end 
    pid = spawn_link(fn -> recur.(recur, run) end) 
    {pid, ref} 
    end 

    def apply({pid, ref}) do 
    send(pid, {ref, :run}) 
    end 

    def cancel({pid, ref}) do 
    send(pid, {ref, :cancel}) 
    end 
end 

の例を見てみましょう:

iex> deb = Debounce.start(fn -> IO.puts("Hello"), 5000) 
iex> Debounce.apply(deb) 
iex> Debounce.apply(deb) 
# wait some time 
Hello 
iex> Debounce.apply(deb) 
iex> Debounce.cancel(deb) 
# wait some time 
# nothing 

これはまだいくつかの可能なコーナーケースを持っている - 製品版は、おそらく、タスクやGenServerを使用します。

関連する問題