2009-10-10 7 views
9

以下はerlang関数です。私はどのようにリスト:マップ関数がここで使用されるのか分かりません。 誰か説明できますか?erlangリストの使い方:map関数

% perform M runs with N calls to F in each run. 
% For each of the M runs, determine the average time per call. 
% Return, the average and standard deviation of these M results. 

time_it(F, N, M) -> 
     G = fun() -> F(), ok end, 
     NN = lists:seq(1, N), 
     MM = lists:seq(1, M), 
     T = lists:map(
      fun(_) -> 
      T0 = now(),    % start timer 
      [ G() || _ <- NN ],   % make N calls to F 
      1.0e-6*timer:now_diff(now(), T0)/N % average time per call 
     end, 
     MM 
     ), 
     { avg(T), std(T) }. 

ありがとうございました。

また、私はこの機能を使用するときに正しい構文を知らない。たとえば、dummy()関数は1つのパラメータを取ります。ダミー関数を時間を計ろうとしているときにエラーが発生します。

moduleName:time_it(moduleName:dummy/1, 10, 100). 

上記は不正な表現であると評価されます。

は実際には、正しい構文で、関数がで正しく呼び出すことができます。

moduleName:time_it(fun moduleName:dummy/1, 10, 100). 

しかし、それは任意のパラメータを渡すことなく、ダミー関数を呼び出すと言って例外がスローされます。私はこの行が悪人だと思う、[ G() || _ <- NN ],私はそれを修正する方法が全くわからない。

+1

'F()' NN回を直接呼び出すのではなく、 'G = fun() - > F()、ok end'の理由は? – Zed

+0

私が最初に推測したのは、F()の出力をリストの理解度に累積して処理を遅らせた場合の誤った最適化であるということでした。だから私はそれを試して、それは違いがあります!あなたのFが255の整数のリストのようなものを出力した場合、リストの中でG()を呼び出すよりも十分な時間を実行するのが遅くなります。おそらく、これはリストを構築するオーバーヘッドが原因です。 リストを使用する:foreachはより良い解決策です。これはリストの理解よりもはるかに高速で、関数をネストする必要はありません。 –

答えて

6

mapMMは、各要素に対して機能

T0 = now(),       % start timer 
[ G() || _ <- NN ],     % make N calls to F 
1.0e-6*timer:now_diff(now(), T0)/N % average time per call 

を実行するためにここで使用されます。 mapは、同じサイズの新しいリストを返します。ここで、新しいリストの各要素は、対応する要素に上記の関数を適用した結果です。MMです。これらにより

moduleName:time_it(fun moduleName:dummy/1, 10, 100). 
0
results(N, F) when N >= 0 -> results(N, F, []). 
results(0, _, Acc) -> lists:reverse(Acc); 
results(N, F, Acc) -> results(N-1, F, [F() | Acc]). 

repeat(0, F) -> ok; 
repeat(N, F) when N > 0 -> 
    F(), 
    repeat(N-1, F). 

T = results(M, fun() -> 
        T0 = now(), 
        repeat(N, G), 
        1.0e-6 * timer:now_diff(now(), T0)/N 
       end) 

メイクセンス、今

あなたのようなtime_itを呼び出すことができますか?

1

あなたは、関数moduleNameの持っている場合:ダミー/ 1をあなたはそれがF(constant_parameter)代わりのF()を呼び出して行い、その後、time_it/3を編集することができた場合は、次の

  1. のいずれかを実行することができます。私はこれが当てはまると仮定します。
  2. それ以外の場合は、M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M)に電話してください。 ダミーは直接呼び出されるのではなく、time_it内のFによってのみ呼び出されます。
4

関数のlists:mapの目的は、単に内部関数M回を実行することです。あなたはこのパターンを見たとき:

L = lists:seq(1,M), 
lists:map(fun(_)-> Foo() end, L) 

それだけでは何度も何度もM回Foo()を呼び出して、リスト内の各呼び出しの結果を返すことを意味します。実際には整数のリストを[1,2,3,...N]とし、リストの各メンバに対してFoo()を1回呼び出します。
time_itの著者は、time_itがあなたにN * M回与える関数を呼び出す必要があるので、この同じトリックをやり直します。だから彼らは、内側のループN回実行するために、異なる技術を使用してM回実行し、外側のループの内側:

L = lists:seq(1,N), 
[Foo() || _ <- L] 

これは、上記のコードとまったく同じ結果になりますが、今回FooはN回と呼ばれています。

あなたのダミー関数とのtime_itを使用してトラブルを抱えている理由は、time_itが0のパラメータではなく、1ですから、ダミー関数を作成し、このようにそれを呼び出す必要がありますと機能を取ることである:何

dummy() -> 
    %% do something here you want to measure 
    ok. 

measure_dummy() -> 
    time_it(fun someModule:dummy/0, 10, 100). 
関連する問題