2015-05-25 13 views
12

Próbuję zaimplementować środek, który zachowuje się jak kostki:Elixir - Randomizowane numery w Agenta

defmodule Dice do 
    @on_load :seed_generator 

    def start_link(opts \\ []) do 
    Agent.start_link(fn -> [] end, name: __MODULE__) 
    end 

    def roll(n, val) do 
    Agent.cast(__MODULE__, fn(_) -> 
     Stream.repeatedly(fn -> :random.uniform(val) end) 
     |> Enum.take(n) 
    end) 
    end 

    def seed_generator do 
    :random.seed(:erlang.now) 
    :ok 
    end 
end 

Jednak wygenerowane numery są takie same, za każdym razem, gdy ponownie uruchomić iex. Co robię źle? Czy materiał siewny nie działa, ponieważ wywołanie :random.uniform znajduje się wewnątrz agenta? Lub może coś związanego z Stream.

Odpowiedz

8

Funkcja seed_generator jest wywoływana w innym procesie niż ten, z którego będzie korzystał Twój Agent. W rzeczywistości proces ten nie istnieje nawet w momencie załadowania tego kodu. Spróbuj wysiewu generator podczas uruchamiania Agent:

defmodule Dice do 
    def start_link(opts \\ []) do 
    Agent.start_link(fn -> :random.seed(:erlang.now) end, name: __MODULE__) 
    end 

    def roll(n, val) do 
    Agent.get(__MODULE__, fn(_) -> 
     Stream.repeatedly(fn -> :random.uniform(val) end) 
     |> Enum.take(n) 
    end) 
    end 
end 
+0

wydaje się działać, to zrobił: 'Agent.start_link (FN ->: random.seed (: erlang.now); [] koniec, nazwa: __MODULE __)' aby zachować pustą listę jako stan domyślny. Dziękuję Ci. – Kernael

+0

W każdym razie ignorujesz ten stan w funkcji "roll", więc nie sądzę, żeby to miało znaczenie. Twój aktualny stan to słownik procesu, w którym jest przechowywany stan generatora losowego. –

+2

Zamiast funkcji erlang.now(), funkcja os.timestamp() może być również dobra: http://www.erlang.org/doc/man/os.html#timestamp-0 Ponieważ erlang.now() może przynieść trochę problemów. – h4cc