Ada 2020 (5日目) - delta aggregate

そろそろ疲れが出てきました。 簡単なので済ませます。

経緯

SPARKという、Adaのサブセットに静的な検証機能を追加したAdaCore社の製品がありまして。 そのSPARKでは様々な条件を式として書く必要があります。

type Rect is record
   Left, Right, Top, Bottom : Float;
end record;

というようなrecordがあるとして、この型のオブジェクトの一部分だけを変更したいとします。

procedure Set_Left (X : in out Rect; New_Left : in Float) is
begin
   X.Left := New_Left;
end Set_Left;

このサブプログラムに検証のための事後条件を書き足します。

procedure Set_Left (X : in out Rect; New_Left : in Float)
  with Post =>
    X.Left = New_Left and X.Right = X'Old.Right
      and then X.Top = X'Old.Top and then X.Bottom = X'Old.Bottom;

最初の andand then ではないのはその前の条件中の X.Left がサブプログラム実行後の値を参照しているため短絡評価にしてしまうと実行前に 'Old を保存していいかわからなくなるからです。 無条件に保存すれば良いと思われるかもしれませんが場合によっては例外になるかもしれない式(配列の範囲外アクセス等)に 'Old が付けられているかもしれませんのでなるべく保存しないような仕様になっています。

ちなみにこのPostの構文はAda 2012にも採用されています。 SPARKですと静的に検証されますが、Adaとしての動作は実行時の検証となります。

それで、まあ、やってられませんね。 この例では Rect ですからまずありえませんけれども、もし要素数が増えたら漏れが出そうです。

そうなると必要になるのが、関数型言語にある構造体の一部を更新する式です。 例えばObjective Camlですと、こう書けます。

type rect = {
  mutable left: float;
  mutable right: float;
  mutable top: float;
  mutable bottom: float};;

let set_left (x: rect) (new_left: float) = x.left <- new_left;;

(* OCamlには検証の機能はないため実際に動かして確認 *)
let x = {left = 1.0; right = 2.0; top = 3.0; bottom = 4.0};;
let old_x = (Obj.obj (Obj.dup (Obj.repr x)): rect);; (* clone *)
set_left x 5.0;;
assert (x = {old_x with left = 5.0});; (* このwith構文です *)

Haskellですと元の値が { } の外に来ます。

x == old_x {left = new_left}

というわけでSPARKにもこの機能が独自に追加されました。

procedure Set_Left (X : in out Rect; New_Left : in Float)
  with Post =>
    X = X'Old'Update (Left => New_Left);

この構文がAda 2020にも提案されましたが却下されました。 これは見ての通り属性の構文を流用したものです。 Adaでは属性は関数の形を取るようになっていて、可変パラメータな上に配列の場合は数値や範囲を取れされもするこの 'Update は馴染まないとかなんとか。

Ada 2020での改善

代わりに提案されたのが予約語 delta を再利用した構文です。

procedure Set_Left (X : in out Rect; New_Left : in Float)
  with Post =>
    X = (X'Old with delta Left => New_Left);

元の値が括弧の中だからObjective Caml派! というわけではなく、Adaには元々、基底型の値に派生型の要素を追加して派生型の値を作るextension aggregateという機能がありましたので、それに倣った形です。

delta は固定小数点数の刻み幅に使われていた予約語です。 Adaではたまにこういう予約語の再利用があります。

関連AI