2

基本的に、値と ID のリストを含む構造があります。私がやりたいのは、IDのリストをマップしてそれらにメッセージを送信することですが、IDのリストを最初に初期化するときに、変数「empty_set」を配置します(名前をempty_listに変更する必要があるかもしれません:P)。

問題は、マップ関数を呼び出すたびに、リストが「empty_set」であるかどうかを最初に確認し、そうでない場合はマップ関数を使用することです。コードは次のとおりです。

{From, set_value, V} ->
  if ViewerSet /= empty_set -> set_viewer_values(V, ViewerSet)
  end,
looper(V, ViewerSet)

呼び出される関数は次のとおりです。

set_viewer_values(Value, ViewerSet) ->
  if ViewerSet /= empty_set ->
    lists:map(fun(ViewerPid) ->
        ViewerPid ! {self(), set_value, Value} end, ViewerSet)
  end.

これは私がプロセスを開始する方法です:

process() ->
  C = spawn(fun() -> looper(no_value, empty_set) end),
  {ok, C}.

問題は、実行すると次のエラーが発生することです。

=ERROR REPORT==== 2-Nov-2014::15:03:07 ===
Error in process <0.367.0> with exit value: {function_clause,[{lists,map,
[#Fun<sheet.2.12938396>,empty_set],[{file,"lists.erl"},{line,1223}]},{lists,map,2,
[{file,"lists.erl"},{line,1224}]},{sheet,cell_loop,2,[{file,"sheet.erl"},{line,93}]}]}

私が理解していることから、リストが空かどうかを確認する必要がある if 式にもかかわらず、リストをマップしようとします。

では、表現のどこが間違っているのでしょうか。

ありがとう

4

4 に答える 4

3

パターンマッチング。ガード内の空のリストをチェックする必要がある場合、ifまたはcondErlang についての考え方に構造的な問題があることがほぼ確実な場合。

これはほとんどの場合、紛らわしいコードや、「空のリストをチェックするにはどうすればよいか」などを自問する奇妙なエッジ ケースとして現れます。あなたが本当に求めているのは「手続き条件として空のリストをチェックするにはどうすればよいですか?」ということであることに気付かずに。これは、健全な関数型プログラミングの悩みの種です。

編集:もう少し説明と例が適切かもしれません

パターンマッチングを挿入したい場合はいつでも、ケースのようなものを使用するか、実行していることを別の関数に分割できます。非常に多くの場合、一方では物事が密結合しすぎており ( 内でメッセージの受信以外の作業を行っているreceive)、他方では緩すぎています (実際にパラメーターを一致させることが自然な解決策である場合、関数を呼び出す前に多くの任意の手続き型チェックを行います)。

looper(V, ViewerSet) ->
  receive
    {From, set_value, V} ->
        set_viewer_values(V, ViewerSet),
        looper(V, ViewerSet);
%   OtherStuff ->
%       whatever else looper/2 does...
  end.

set_viewer_values(V, []) ->
    set_default_values(V);
set_viewer_values(V, ViewerSet) ->
    % ... whatever the normal function definition is...

レシーブ内から発信する場所は、実際の作業を行うべき場所であり、マッチングを行いたい場所でもあります。それはとにかく関数呼び出しであるため、ここでのマッチングは適切であり、コードを簡素化します。

それ自体を一致させたい場合、looper/2これは確かに可能です。空のリストを受け取ったときに何をしたいのかわからないので、何かを作成しますが、やりたいことは何でもできます。

looper(V, []) ->
    looper(V, default_set());
looper(V, ViewerSet) ->
    % As before, or whatever makes sense.

空のセットがある場合は、まったく異なる方法で操作する必要があると判断することもできます。

full_looper(V, []) ->
    empty_looper(V);
full_looper(V, ViewerSet) ->
  receive
    {new_set, Set} ->
        looper(V, Set);
    {From, set_value, V} ->
        set_viewer_values(V, ViewerSet),
        looper(V, ViewerSet)
  end.

empty_looper(V) ->
  receive
    {new_set, Set} ->
        full_looper(V, Set);
    {From, set_value, V} ->
        set_viewer_values(V, default_set()),
        empty_looper(V)
  end.

上記の私のポイントは、任意の手続き型チェックに頼らずに空のセットを持つ場合を処理する方法がたくさんあり、方法を知っていればすべて簡単に読めるということです (ただし、この方法で物事を行うことに慣れるまでは、かなり奇妙に感じるかもしれません)。余談ですが、最後の例は実際に有限状態マシンを作成するもので、FSM の作成を非常に簡単にする OTP モジュールが既にあります。(Erlang で手で書くのも簡単ですが、gen_fsmモジュールを使えばさらに簡単です。)

ケースを試して、再帰ではなくリストが空であることを確認してください。

于 2014-11-02T15:02:03.070 に答える
0

If you have a list of ids in the variable ViewerSet, simply initialize it with the empty list: [].

Then when you receive the message {From, set_value, V} you can execute a function for each element of the list (even if it is empty) using lists:foreach/2 or using list comprehension:

{From, set_value, V} ->
  lists:foreach(fun(ViewerPid) -> ViewerPid ! {self(), set_value, Value} end, ViewerSet),
  looper(V, ViewerSet);
...

or

{From, set_value, V} ->
  [fun(ViewerPid) -> ViewerPid ! {self(), set_value, Value} end || ViewerPid <- ViewerSet],
  looper(V, ViewerSet);
...
于 2014-11-02T20:08:17.043 に答える
0

あなたのコードに基づいて、これはあなたが得るべきものです:

(shell@a)8> Val.
myatom
(shell@a)9> if Val /= myatom -> lists:map(fun(X) -> io:format("~p",[X]) end, Val) end.
** exception error: no true branch found when evaluating an if expression
(shell@a)10> 

したがって、問題は別の場所にあるようです。

于 2014-11-22T01:41:20.827 に答える
0

両方のif式で、 が ? の場合ViewerSetはどうなりempty_setますか? この事件を処理する警備員はいません。

ifErlang のif式は、他の言語で見られる典型的な式ではありません。私が持っているほとんどの経験から、それらはほとんど回避され、正当な理由があります: (別の回答が既に述べたように) パターン マッチングを使用して、(ガードを介して) 等値やその他の比較操作をチェックできます。

以下はここから取られます:

ガード シーケンスが真でない場合、if_clause実行時エラーが発生します。必要に応じtrueて、最後の分岐でガード式を使用できます。これは、ガード シーケンスが常に真であるためです。

例:

is_greater_than(X, Y) ->
    if
        X>Y ->
            true;
        true -> % works as an 'else' branch
            false
    end

したがってif、式は一種のものになりcaseますが、句としてブール値を使用すると、明確さよりも混乱が生じる傾向があります。一部の人々は、の使用を一切if避けています。

私の提案は、式を使用している自分を見るたびに、関数句または関数句の一部としてif、それをパターン マッチングに置き換える方法を自問することです。case

于 2014-11-02T16:50:17.677 に答える