Ada 202x (9日目) - declare expression¶
日が変わる前に間に合ったからセーフ。
経緯¶
Ada 2012で、式としての if
や case
(conditional expression)、quantified式が使えるようになりました。
if式。折り返しを微妙に迷います。
(if A = B then X
elsif C = D then Y
else Z)
case式。
(case A is
when B => X,
when C => Y,
when others => Z)
quantified式。
Boolean
限定のfold式みたいなものです。
for all
はループ全てが条件を満たせば、 for some
はループ中1回でも条件を満たせば True
になります。
(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¶
式中での宣言もできるようになりました。 ……ヘンな文法で。
(declare
X : constant T := V;
begin
F (X))
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
で型を省略できるようになりました。
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);
え、式を renames
するのはありですかって?
それは式によります。
この場合は (First + Last) / 2
の一番外側は /
演算子です。
そして /
演算子は "/"
関数の呼び出しです。
関数呼び出しの結果は一時オブジェクトですので renames
も可能というわけです。
型名の省略は普通に文指向で書いているときにも有用です。 というわけで見慣れた形に書き直したものがこちら。
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でもようやくですね。
<読み飛ばし推奨> 個人的にはこれを型推論と呼ぶ風潮には反対します。 右辺をコンパイルする過程で型は特定できていますから型名を書いた場合と比べても何も推論してはいません。 </読み飛ばし推奨>
関連AI¶
AI12-0236-1 declare expressions
AI12-0275-1 Make subtype_mark optional in object renames
所感¶
足りないのは末尾再帰最適化ですって? バックエンドに言ってください。