読者です 読者をやめる 読者になる 読者になる

てきとう

てきとう

'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:お察しの通り、配列は配列なので再起的ではありません。

1からやり直し:hello, world編

基本

with Ada.Text_Io;
procedure Hello is
begin
   Ada.Text_Io.Put_Line("hello, world");
end Hello;

応用:use

with Ada.Text_Io;
use Ada.Text_Io;
procedure Hello is
begin
   Put_Line("hello, world");
end Hello;

応用:renames

with Ada.Text_Io;
procedure Hello is
   package TIO renames Ada.Text_Io;
begin
   TIO.Put_Line("hello, world");
end Hello;

宣言時にrenamesを使うと別名として宣言できます。
パッケージに短く適当な別名をつけることで、書く際の負担を減らしつつ可読性を上げることができます。

【テスト】Mountain LionでGCCを--enable-languages=adaでビルドしてみた記憶【コピペ】

*1

お久しぶりですが別に何もありません。いつも通りのダメ人間です。
適当にやってもできなかったけど適当に調べたらできたので記録というか記憶をメモ。
記憶なので細かいところ違うかと。

用意するもの

  • 動くGNAT。今回はgnuadaの4.6.0を使用。
  • gccのソース。今回は4.7.1。
  • gccのビルドに必要らしいGMPとかMPFRとかMPCとか。細かくは忘れたのでドキュメント参照してください。
    • MacportsだのFinkだのHomebrewだのをお勧めします。

手順

ここここを参考にやりましたので、そちらを見ることをお勧めします。
まとめると、要点はconfigureに以下をくっつけること。

CC='gcc -D_FORTIFY_SOURCE=0'

というわけでconfigureだけ気をつければいいので、gnuadaのGNATにパス通して

$ ./configure CC='gcc -D_FORTIFY_SOURCE=0' \
--enable-languages=c,c++,ada \
--prefix=$SOMEWHERE \
--build=x86_64-apple-darwin12
(略)
$ make
(略)
$ make install
(略)

こんな感じで動いてそうなGNATができました。


ちなみにCC=...を忘れるとldが「x86_64でこのシンボル知らねーよ!」とだかよく分からない暴言を吐いてconfigureに失敗します。
そのうち直ることを期待しときましょう。

*1:先程はてダに書いたもののコピペです。