Ada 202x (9日目) - declare expression ===================================== .. post:: Dec 09, 2019 :tags: ada, ada_2022 日が変わる前に間に合ったからセーフ。 経緯 ---- Ada 2012で、式としての ``if`` や ``case`` (conditional expression)、quantified式が使えるようになりました。 if式。折り返しを微妙に迷います。 .. code-block:: ada (if A = B then X elsif C = D then Y else Z) case式。 .. code-block:: ada (case A is when B => X, when C => Y, when others => Z) quantified式。 ``Boolean`` 限定のfold式みたいなものです。 ``for all`` はループ全てが条件を満たせば、 ``for some`` はループ中1回でも条件を満たせば ``True`` になります。 .. code-block:: ada (for all I in 1 .. 10 => F (I)) -- F (1) and then F (2) and then ... F (10) (for some I in 1 .. 10 => F (I)) -- F (1) or else F (2) or else ... F (10) Haskellの ``Data.Foldable.all`` や ``Data.Foldable.any`` と思えばいいです。 (伝わらない説明。) これらは、同じくAda 2012で導入された事前条件/事後条件等の条件式に複雑な式を書くために導入されました。 またAda 2012の改訂版であるTechnical Corrigendum 1で ``raise`` も式中で使えるようになり、例外が投げられるようになりました。 そしてAda 202xではaggregate式で内包表記っぽいこともできるようになっています。 そう、手続き型言語Adaは既に式指向の言語として色々書けてしまうのです。 流行にかぶれてしまってますよねえ。 となると後足りないものは何でしょうか。 Ada 202xでのdeclare expression ------------------------------ 式中での宣言もできるようになりました。 ……ヘンな文法で。 .. code-block:: ada (declare X : constant T := V; begin F (X)) .. code-block:: ada type Float_Array is array (Positive range <>) of Float; Not_Found : exception; function Binary_Search (C : Float_Array; Item : Float) return Positive is (if C'Length > 0 then (declare M : constant Positive := (C'First + C'Last) / 2; begin (if C (M) > Item then Binary_Search (C (C'First .. M - 1), Item) elsif C (M) < Item then Binary_Search (C (M + 1 .. C'Last), Item) else M)) else raise Not_Found); 珍しい ``begin`` 単独での使用は珍しく珍しいですね。 declare式で宣言できるものは変数や定数と ``renames`` による別名に制限されていますので、型や関数内関数等は宣言できません。 関数内関数が使えれば無法地帯でしたのに残念。 Ada 202xでのrenamesの改善 ------------------------- 式中に書くには ``constant 型名`` というのは長い、と思われたようです。 色々と提案された結果最終的に ``renames`` で型を省略できるようになりました。 .. code-block:: ada function Binary_Search (C : Float_Array; Item : Float) return Positive is (if C'Length > 0 then (declare M renames (C'First + C'Last) / 2; begin (if C (M) > Item then Binary_Search (C (C'First .. M - 1), Item) elsif C (M) < Item then Binary_Search (C (M + 1 .. C'Last), Item) else M)) else raise Not_Found); .. container:: strike え、式を ``renames`` するのはありですかって? それは式によります。 この場合は ``(First + Last) / 2`` の一番外側は ``/`` 演算子です。 そして ``/`` 演算子は ``"/"`` 関数の呼び出しです。 関数呼び出しの結果は一時オブジェクトですので ``renames`` も可能というわけです。 型名の省略は普通に文指向で書いているときにも有用です。 というわけで見慣れた形に書き直したものがこちら。 .. code-block:: ada function Binary_Search (C : Float_Array; Item : Float) return Positive is First : Positive := C'First; Last : Natural := C'Last; begin while First <= Last loop declare M renames (First + Last) / 2; begin if C (M) > Item then Last := M - 1; elsif C (M) < Item then First := M + 1; else return M; end if; end; end loop; raise Not_Found; end Binary_Search; ちなみに古代言語Modula-2ですら変数宣言時の型名の省略は可能でした。 今回採用されたのは ``renames`` のみと限定された形ですが、Adaでもようやくですね。 .. container:: gray-and-small <読み飛ばし推奨> 個人的にはこれを型推論と呼ぶ風潮には反対します。 右辺をコンパイルする過程で型は特定できていますから型名を書いた場合と比べても何も推論してはいません。 関連AI ------ - `AI12-0236-1`_ **declare expressions** - `AI12-0275-1`_ **Make subtype_mark optional in object renames** 所感 ---- .. container:: gray-and-small 足りないのは末尾再帰最適化ですって? バックエンドに言ってください。 .. _`AI12-0236-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0236-1.txt .. _`AI12-0275-1`: http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ai12s/ai12-0275-1.txt