てきとう

てきとう

'Firstからやりなおし:現実逃避編

色々疲れたので現実逃避。
関数プログラミングの楽しみ」という本がありまして。*1

関数プログラミングの楽しみ

関数プログラミングの楽しみ


中身はHaskellなんですが、3章の「おりがみプログラミング」の(un)foldは再帰的な型があれば他の言語でも(やる意味はともかく)実装できます。
ところでAdaには配列というものがあります。*2
という訳で、どういう訳だか配列で(un)foldっぽいものを作ってみようと思い立ちました。
fold/unfoldそのものと、その便利な使い方については上の本を読んでください。

やる意味

なし

使い勝手

悪い

効率

悪い

特徴

  • 無駄にgeneric使う
  • 無駄にexpression functions使ってみる

ソースとか

origami.ads

仕様。無駄にgeneric。

pragma Ada_12;
generic
   type Index_Type is (<>);
   type Element_Type is private;
   type Array_Type is array (Index_Type range <>) of Element_Type;
package Origami is
   
   generic
      type Result_Type is private;
   function Fold_R (F : access function (E : Element_Type; SoFar : Result_Type) return Result_Type;
                    I : Result_Type;
                    S : Array_Type)
                   return Result_Type;
   
   generic
      type Input_Type is private;
      with function "&"(Left, Right : Array_Type) return Array_Type is <>;
   function Unfold_R (End_Of_Input : access function (I : Input_Type) return Boolean;
                      Element      : access function (I : Input_Type) return Element_Type;
                      Renew_Input  : access function (I : Input_Type) return Input_Type;
                      Input        : Input_Type)
                     return Array_Type;
   
end Origami;
origami.adb

A'Length=0な配列Aの簡単な書き方が分からなくて右往左往。

pragma Ada_12;
package body Origami is
   
   function Unfold_R (End_Of_Input : access function (I : Input_Type) return Boolean;
                      Element      : access function (I : Input_Type) return Element_Type;
                      Renew_Input  : access function (I : Input_Type) return Input_Type;
                      Input        : Input_Type)
                     return Array_Type is
      (if End_Of_Input(Input) then (Index_Type'Succ(Index_Type'First)..Index_Type'First => <>)
      else Array_Type'(Index_Type'First=>Element(Input))
        & Unfold_R(End_Of_Input, Element, Renew_Input, Renew_Input(Input)));
      
      
   function Fold_R(F : access function (E : Element_Type; SoFar : Result_Type) return Result_Type;
		   I : Result_Type;
                   S : Array_Type) return Result_Type is
      (if S'Length=0 then I
      else F(S(S'First), Fold_R(F, I, S(Index_Type'Succ(S'First) .. S'Last))));
      
end Origami;
テストしてみた
pragma Ada_12;
with Ada.Text_Io;
with Origami;
procedure Origami_Test is
   type Nat_Arr is array(Positive range <>) of Natural;
   package O is new Origami (Index_Type => Positive,
                             Element_Type => Natural,
                             Array_Type => Nat_Arr);
   
   function Eq_0 (N : Natural) return Boolean is (N = 0);
   function Mod_2 (N : Natural) return Natural is (N mod 2);
   function Div_2 (N : Natural) return Natural is (N / 2);
   
   function G is new O.Unfold_R(Input_Type => Natural);
   
   A : Nat_Arr := G(Eq_0'Access, Mod_2'Access, Div_2'Access,
                    Natural'Value(Ada.Text_Io.Get_Line));
   function F is new O.Fold_R(Result_Type => Natural);
   function Mul (E : Natural; SoFar : Natural) return Natural is (SoFar*2+E);
       
begin
   for E of reverse A loop
      Ada.Text_Io.Put(E'Img);
   end loop;
   Ada.Text_Io.New_Line;
   Ada.Text_Io.Put_Line(Natural'Image(F(Mul'Access,0,A)));
end Origami_Test;
なんとなく動いてる気がする
123456
 1 1 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0
 123456

しかし実際無駄な。
あ、あとそろそろHaskellもちゃんとやりたい。

*1:多分定価分以上の価値はある内容のようなのに、私は500円分も分かってなくて凄く悔しい一冊です。

*2:お察しの通り、配列は配列なので再起的ではありません。