Ada 202x (8日目) - iterator filter ================================== .. post:: Dec 08, 2019 :tags: ada, ada_2022 順調に投稿時刻が後にずれていっております。 なお毎日のリハビリですので書き溜めはしないようにしております。 これまでのあらすじ ------------------ Adam Beneschan先生の提案parameterized array component associationはわずかな変更でAdaという言語に大きな影響を与えました。 刺激を受けたTucker Taft先生がaggregate式をもっと発展させようとした結果、どんどん内包表記っぽいことになっております。 Ada 202xでのiterator filter --------------------------- ``for`` ループとaggregate式中のparameterized array component associationに ``when`` で条件を書くことができます。 条件を満たさない試行は飛ばされます。 先に例で用いるユーザー定義コンテナを宣言しておきます。 .. code-block:: ada declare package Integer_Sets is new Ada.Containers.Ordered_Sets (Integer); S : constant Integer_Sets.Set := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; for文の場合。 偶数のみ出力します。 .. code-block:: ada begin for I in S.Iterate when S (I) rem 2 = 0 loop Put (S (I)); end loop; 勿論 ``in`` ではなく ``of`` 形式でもフィルタは使えます。 ``of`` はAda 2012からの形式で、復習しますと ``in`` はインデックス(``Cursor``、C++で言うイテレータ)をパラメータとするループで ``of`` は値そのものをパラメータとして受け取るループです。 .. code-block:: ada begin for E of S when E rem 2 = 0 loop Put (E); end loop; aggregate式の場合。 .. code-block:: ada declare X : Integer_Sets.Set := [for E of S => when E rem 2 = 0]; ``X`` には偶数のみが格納されます。 このようにparameterized array component associationでも ``of`` は使えます。 これも配列のときに説明しそびれました。 ``in`` はnamed association 、 ``of`` はpositional associationに対応します。 この例ですと ``Ada.Containers.Ordered_Sets`` はnamed associationをサポートしていませんので ``in`` で書くことはできません。 ``Ada.Containers.Ordered_Maps`` であればキーと値のペアによるnamed associationをサポートしていますので ``in`` で書くことができます。 .. code-block:: ada declare package Integer_Maps is new Ada.Containers.Ordered_Maps (Integer, Integer); Y : constant Integer_Maps.Map := [for I in S.Iterate when S (I) rem 2 = 0 use S (I) => S (I) + 1]; ``Y`` は ``[2 => 3, 4 => 5, 6 => 7, 8 => 9, 10 => 11]`` となります。 この短い式で ``Set`` から ``Map`` へ中身を移せたことにも注目です。 内包表記がマップ関数とフィルタ関数を兼ねることができるのと、同じことができています。 以前インデックスが連続である必要があるため配列ではフィルタは使えません、と書きましたが、補足しておきますとループする対象としては配列は使用できます。 フィルタが使えないのは配列を出力先の型とする場合です。 (違っているかもしれません。もしかしたら ``others =>`` で抜け番を補えば配列でも使えるかもしれません。) そのため配列からユーザー定義コンテナにマップする場合はフィルタも使えます。 for文でも常に使えます。 .. code-block:: ada begin for I in 1 .. 10 when rem 2 = 0 loop Put (I); end loop; まあでも上の例もそうですがfor文の場合は続けてif文を書く場合に比べてインデントを1段省略できる程度の意味しかありません。 .. code-block:: ada begin for I in 1 .. 10 loop if I rem 2 = 0 then Put (I); end if; end loop; aggregate式で使ってこその機能です。 組み合わせ例 ------------ 説明しそびれていたこともありましたので、ここまで紹介した機能を組み合わせた例を挙げておきます。 positional association。 .. code-block:: ada [for E of C => Map (E)] positional association。フィルタ付き。 .. code-block:: ada [for E of C when Filter (E) => Map (E)] named association。インデックスはそのまま。 .. code-block:: ada [for I in C.Iterate => Map (I)] named association。インデックスはそのまま。フィルタ付き。 .. code-block:: ada [for I in C.Iterate when Filter (I) => Map (I)] named association。インデックスも変更。 .. code-block:: ada [for I in C.Iterate use To (I) => Map (I)] named association。インデックスも変更。フィルタ付き。 .. code-block:: ada [for I in C.Iterate when Filter (I) use To (I) => Map (I)] 関連AI ------ - `AI12-0250-1`_ **Iterator Filters** - `AI12-0327-1`_ **Clarify iterator filter wording for aggregates** .. _`AI12-0250-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0250-1.txt .. _`AI12-0327-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0327-1.txt