これは、アキュムレータとパターン マッチングを使用して解決できます。
-module(t).
-export([transform/1]).
transform(List) ->
transform(List, []).
transform([], Acc) ->
lists:reverse(Acc);
transform(["("|T], Acc) ->
transform(T, {[],Acc});
transform([")"|T], {L,{L2,Acc}}) ->
transform(T, {[lists:reverse(L)|L2],Acc});
transform([")"|T], {L,Acc}) ->
transform(T, [lists:reverse(L)|Acc]);
transform([H|T], {L,Acc}) ->
transform(T, {[H|L],Acc});
transform([H|T], Acc) ->
transform(T, [H|Acc]).
このtransform/1
関数は、 の空のアキュムレータを設定するだけでtransform/2
、すべての作業が完了します。
関数は、transform/2
複数のパターン マッチング再帰句に分割されます。
最初の句は、入力リストを使い果たした場合を処理し、単純に逆アキュムレータを返します。アイテムがアキュムレータにプッシュされるため、反転が必要であり、逆の順序になります。これは、Erlang やその他の関数型言語でよく見られるパターンです。
2 番目の句"("
は、新しいサブリストを開始する を認識します。これを処理するために、アキュムレータを 2 タプルに変更します。最初の項目はサブリスト アキュムレータで、2 番目の項目は古いアキュムレータです。
3 番目と 4 番目の句")"
は、サブリストを終了する handle です。3 番目の節は、accumulator がタプルでもある 2 番目の要素を保持するタプルである場合のためのものです。新しいサブリストを項目として前のサブリストに追加し、アキュムレータ タプルから 1 レベルをポップします。4 番目の句は、タプルの元のアキュムレータがリストである場合を処理し、元のアキュムレータの先頭に新しいサブリストを追加して、新しいアキュムレータ リストを形成します。
5 番目と 6 番目の句は、グループ化演算子ではない入力項目を処理します。5 番目の節はアキュムレータがタプルの場合を処理し、6 番目の節はアキュムレータがリストの場合を処理します。
元の例でこれを実行すると、正しい答えが表示されます。
1> c(t).
{ok,t}
2> t:transform(["0", "(", "1", "2", "3", ")"]).
["0",["1","2","3"]]
ただし、ネストされたグループも処理できます。
3> t:transform(["0", "(", "11", "22", "(", "333", "444",
"(", "5555", ")", "666", ")", "77", "88", ")", "9"]).
["0",["11","22",["333","444",["5555"],"666"],"77","88"],"9"]