ushidayの日記

主に「IBMi」のメモに・・・

doxygenとgraphvizを使ったドキュメント作成

doxygengraphvizというツールを使って、APIリファレンスと簡単な関連図の作成が行なえます。doxygen自体はCから派生しているようで、色々な言語に対応している様です。
ドキュメント書式もphpDocやjavadocと近いようです。phpDocの書式で、そのまま実行したら、若干警告が出ましたが全く使えないというレベルではありませんでした。
graphvizここから”graphviz-2.26.3.msi(2010.7.27現在)”が、ダウンロードできます。
doxgenはここから”doxygen-1.7.1-setup.exe(2010.7.27現在)”が、ダウンロードできます。

インストールをするとdoxgenが、Doxywizardという、ウィザード形式のドキュメント作成を提供しています。好みの設定をした後は、設定ファイルの保存も出来ます。日本語対応しているのも嬉しいですね。

doxygenのスナップショット








Zend Studio(Eclipse) プラグインのphpDocumentor

Zend Studioにバンドルされている、phpDocumentorを使った際に設定した事の備忘録。ついでxamppの場合も...。

Zend Studioの設定
  • strftime()関数で、タイムゾーンを指定しないと、ドキュメントにそのまま警告まで出力される。→ プラグインphp.iniのタイムゾーンを設定する事で解決。
    • ”C:\Program Files\Zend\Zend Studio i5 - 7.0.2\plugins\org.zend.php.debug.debugger.win32.x86_5.2.26.v20090817\resources\php53\php.ini”および”C:\Program Files\Zend\Zend Studio i5 - 7.0.2\plugins\org.zend.php.debug.debugger.win32.x86_5.2.26.v20090817\resources\php5\php.ini”に「date.timezone = Asia/Tokyo」を追加。
  • ドキュメントのマルチバイト対応。→SmartyテンプレートファイルのエンコードUTF-8に変更。
    • ”C:\Program Files\Zend\Zend Studio i5 - 7.0.2\plugins\com.zend.php.phpdocumentor_7.0.0.v20090826-1200\Resources\phpdocumentor\phpDocumentor\Converters\HTML\frames\templates\好きなどれか\templates”の内の blank.tpl,header.tpl,index.tpl,tpo_frame.tpliso-8895-1をUTF-8すべて変えます。個人的には”HTML:frames:DOM/earthli”を使っています。
  • phpdocの実行は、[Project]→[Generate PHPDoc..]で行います。一度実行した設定をiniファイルに保存できます。
xamppの設定

xamppの場合はpearがバンドルされている思いますので、pearパッケージの中にphpDocumentorがあると思います。無い場合は、”pear install --alldeps phpDocumentor”を実行します。

  • ドキュメントのマルチバイト対応。→SmartyテンプレートファイルのエンコードUTF-8に変更。
    • ”C:\Program Files\xampp\php\PEAR\data\PhpDocumentor\phpDocumentor\Converters\HTML\frames\templates\好きなどれか\templates”の内の blank.tpl,header.tpl,index.tpl,tpo_frame.tpliso-8895-1をUTF-8すべて変えます。
  • phpDocの設定ファイル作成。
    • ”C:\Program Files\xampp\php\PEAR\data\PhpDocumentor\user”内にあるiniファイルをコピーしてオリジナルのiniファイルを作成します。最低でもtarget(doc)とdirecory(src)を変更して保存します。
  • phpdocの実行はコマンドプロンプトで行ないます。
    • cd C:\Program Files\xampp\phpで、phpdocコマンドのカレントに移動。
    • phpdocを実行すると、C:\Program Files\xampp\php\PEAR\data\PhpDocumentor\userにある、iniファイルがリストされる。ので作成したiniファイルの番号を選択。

以上。
■xamppの場合のプロンプト

C:\Program Files\xampp\php>phpdoc
******************************************************************************
* PhpDocument Command-Line  Starter
*
* phpDocumentor is a JavaDoc-like automatic documentation generator for PHP
* written in PHP. It is the most versatile tool for documenting PHP.
*
* This batch-file will try to run the phpDocumentor using the command-line
* version of PHP4. NOTE: It will not run with the PHP ISAPI module!
* Please update the path in this batch-file to your PHP-CLI.
*
* Tip: o Grab a copy of one of the ini-files in the user/ dir of the
*        phpDocumentor and modify the settings there.
*      o To see the command line options type  phpdoc -h
*
* @version 1.3  2003-06-28
* @author Sam Blum sam@blueshoes.org
* @Copyright Free Software released under the GNU/GPL license
*
* This SW was contributed by BlueShoes www.blueshoes.org "The PHP Framework"
******************************************************************************
------------------------------------------------------------------------------
Select Ini-File [default is phpDocumentor.ini]
------------------------------------------------------------------------------
# 0: phpDocumentor.ini
# 1: default.ini
# 2: demo.ini
# 3: error.ini
# 4: makedocs.ini
# 5: testdocbook.ini
# 6: ushida_test.ini
Type a number and press Enter[0]:6

APIリファレンス

Zend ServerにPearを入れる際の

はてなダイアリーが、新しくなって、初めて書いたかも?という位、ご無沙汰ですが...(-_-;)。

自分の使っている、ThinkPad X60にZend Serverは入れてあるのですが、Pearが入って無かった事に、最近気がつきました。

デスクトップPCは、Zend Serverより以前に、xamppが入れてあるので、既にPearがバンドルされており、昔サーバー機やった時の記憶が、「pearインスコ用のbatファイルがあったな」程度しか戻らず、備忘録として残しておきます。

go-pearの実行
    • 「C:\Program Files\Zend\ZendServer\bin」に”go-pear.bat”というbatファイルがあるので実行します。go-pear.batに「-d phar.require_hash=0」の起動オプションを追加します。※2012.03.23追記
    • ”system”, ”local”の何れか聞かれるので”system(デフォルト)”を入力。
    • インストールディレクトリの一覧が表示されます。デフォルトの場合は、インストール先がカレントになっている(この場合は:\Program Files\Zend\ZendServer\bin)ので、”all”を選択して、一覧の1〜12までを適宜変更します。(ex ”C:\ProgramFiles\Zend\ZendServer\share\pear”など)
    • 「C:\Program Files\Zend\ZendServer\share\pear\PEAR_ENV.reg」を実行してレジストリを登録。

以上です。

■go-pear.bat実行時のコマンドプロンプト

Are you installing a system-wide PEAR or a local copy?|local) [system] : system

Below is a suggested file layout for your new PEAR installation.  To
change individual locations, type the number in front of the
directory.  Type 'all' to change all of them or simply press Enter to
accept these locations.

 1. Installation base ($prefix)                   : C:\Program Files\Zend\ZendServer\bin
---- 省略 ----
11. Name of configuration file                    : C:\WINDOWS\pear.ini
12. Path to CLI php.exe                           : C:\Program Files\Zend\ZendServer\bin\.

1-12, 'all' or Enter to continue: all
Installation base ($prefix) [C:\Program Files\Zend\ZendServer\bin] : C:\Program\Zend\ZendServer\share\pear
Temporary directory for processing [$prefix\tmp] :
---- 省略 ----
Path to CLI php.exe [C:\Program Files\Zend\ZendServer\bin\.] :

Below is a suggested file layout for your new PEAR installation.  To
change individual locations, type the number in front of the
directory.  Type 'all' to change all of them or simply press Enter to
accept these locations.

 1. Installation base ($prefix)              : C:\Program Files\Zend\ZendServer\share\pear
---- 省略 ----
12. Path to CLI php.exe                      : C:\Program Files\Zend\ZendServer\bin\.

1-12, 'all' or Enter to continue:
---- ここでEnter ----
Beginning install...
Configuration written to C:\WINDOWS\pear.ini...
---- 省略 ----
* WINDOWS ENVIRONMENT VARIABLES *
For convenience, a REG file is available under C:\Program Files\Zend\ZendServer\share\pear\PEAR_ENV.reg
This file creates ENV variables for the current user.

Haskell読書会5th@ShizuDevをやりました

毎月恒例の第5回Haskell読書会を静岡で開催致しました。
今回はプログラミングHaskellの第6章”再帰関数”です。早いもので、読書会も折り返し地点になりました。
スピーカーは、私が産声をあげた地”豊橋”から、いつも来て頂いている”ふるたさん”に、やって頂きました。名古屋からもわざわざ”クラ●△◇×◎※さん”が、初参加で来て頂きました。東京や名古屋の都市圏から、静岡の勉強会に来て頂けるなんて感無量です。ふるたさん&関係者&参加者のみなさん、ありがとうございました。

内容は参加メンバーの方々が、既にブログでまとめて下さっているので、そちらをご参考に...。

再帰自体は、自身を呼び出したり、相互呼び出ししたりと、難しいお話ではないのですが、今回の章は”何が何でも再帰的”な部分がありました。しかし実際は再帰を知る事により、この後「あそこでは再帰でやったけど、こうやればもっと効率よく解りやすいよ」的な展開になって行くのかな?と個人的には思っております。

再帰関数は、最終的に基底部に、落ち着かないと、永久ループになってしまうので、いかにその基底部のパターンマッチが、パッとスッキリ思いつくかが勝負だと思いました。逆にパターンマッチが直ぐに思いつかないケースは、変テコな実装を考えてしまう事も?...。
再帰の利用ケースは、例題や解説でもそうですが、やはりリスト等の繰り返し処理が多いと思います。Haskellをこれまで勉強してきて、”リスト処理が簡潔にこなせる”(特に部分的に関数を作って、最終的に出来た関数は)という印象がさらに強まった感じです。

不思議な感覚なのは”( n + k )パターン”を使った再帰です。以前の章で「n+kパターンは、将来的に無くなるかも...。あまり積極的に使わない方が...。」みたいなこと書いてあったのですが、今章はバンバン出てきます。例えば2つ整数を引数に取って、積を返す関数”mult”は...。

■(n+k)パターンの例

mult::Integer->Integer->Integer
mult 0 _ = 0
mult _ 0 = 0
mult x 1 = x
mult 1 y = y
mult x (y+1) = x + mult x y

と書けるのですが、xの加算をy回繰り返すのに、(y+1)で受けるという文化が、まだ少し馴染めません。
ついこう書きたくなってしまいます。

mult x y = x + mult x (y-1)

でもむしろ(n + k)パターンの方が、いかにも”Haskell”らしくて好きです。「ザクとは違うんだよ。ザクとは。」みたいな。(でも、非推奨の記法かもしれませんがね...。)

懇親会では富士の「B級グルメ”つけナポリタン”食べるぞ!勉強会」の話で盛り上がっていたので、富士での開催もありそうです。次回は2回目の三島です。その次は、静岡でガンダム公開初日に、ガンダムのある東静岡でやる予定です。その次は浜松。静岡県を東へ西へShizuDevは活動していきます。

今回は、業務連絡が行き届いていなくて、おやつが普段の2倍になってしまいました。その分糖分補給もいつもの2倍。みなさんの頭も2倍スッキリしたカモ?
■今回のおやつ(ドーナツ&磯自慢入チーズケーキ)

Zend_Authでユーザー認証&DB2のencryption

Zend_Authを使った、ユーザー認証をやってみたので、メモをしておきます。
IBM i(AS/400)の既存データベースに存在している社員マスターのユーザーIDとパスワード情報で認証を行います。
Zend_Authは、データベース認証用に”Zend_Auth_Adapter_DbTable”というクラスが用意されています。このクラスは、コストラクタに”Zend_Db_Adapter_xxxxxx”のインスタンスを渡す必要があり、今回のケースでは”Zend_Db”を使っていなかったので、”Zend_Auth_Adapter_Interface”を実装して、オリジナルの”Zend_Auth_Adapter”を作成して認証してみました。

まず、社員マスターの認証をチェックするメソッドを実装します。認証の判定としては

    • 認証成功
    • ユーザーが存在しない
    • 廃止ユーザーで認証不可
    • パスワードのアンマッチ
    • その他のエラー

の5つとします。

encryptionを使ったパスワードの暗号化

話はソレるのですが、先日発表されたPower7のIBM i OS 7.1では、データベース列における暗号化が可能になるそうです。しかし、自分が使っている環境のV5R4では、それが実現出来ませんので、DB2のEncryptを使って暗号化したいと思います。
暗号化したデータを保存する為には、DDLで下の様に”varchar for bit”を定義するか、DDSで”H”タイプのフィールド定義にする必要があります。

--- DDLの場合 ---
ALTER TABLE EMPL ALTER COLUMN PWD SET
DATA TYPE VARCHAR ( 80) FOR BIT DATA NOT NULL

--- DDSの場合 ---
A            PWD           80H         COLHDG(' パスワード ') 

フィールドのLengthについては、マニュアルに以下の様な記載がありました。

パスワードストリングが指定されているが、ヒント・ストリングは
指定されていない場合は、データ・ストリングの長さ属性に16 を足し、
それに次の8バイト境界までのバイト数を足したものになります。

それ以外の場合は、データ・ストリングの長さ属性に48を足し、それに次の8
バイト境界までのバイト数を足したものになります。

だそうです。

次に暗号化から復号化までの手順です。

    • 暗号化パスワード&ヒントの設定「SET ENCRYPTION PASSWORD 'hoge' WITH HINT 'fuga'」これをやると以降のSQLセッションで、グローバル設定になります。若しくは、SQL発行時に列毎にencrypt_rc2やdecrypt_charの第二引数にパスワードを取る事も出来ます。
    • 暗号化処理「encrypt_rc2('暗号化したい値')」又は「encrypt_tdes('暗号化したい値')」
    • 復号化処理「decrypt_char(復号対象列)」

暗号化パスワードは、暗号化する時と復号化する時に必要となります。ヒントはパスワードを忘れた時のヒントになります。ヒントは「select gethint(pwd) from テーブル 」の様にして、見ることが出来ます。
気を付けるのは、暗号化する際に書き込むフィールドは、無変換(CCSID65535)なので、書き込むジョブのCCSIDに左右されると言う事です。パスワード認証を行う際に、”入力パスワードを暗号化したモノ”とDBの暗号化されたパスワードを比較すると、現行のCCSIDと暗号化した時のCCSIDが違うと、当然不一致になります。しかし、”decrypt_char”を使うと、現行ジョブのCCSIDを反映した状態で復号化されるので、DBの暗号化パスワードを復号化した上で、入力パスワードと比較した方が、ジョブのCCSIDに影響される事がなさそうです。
■暗号化されたパスワード

認証処理の実装

■社員のパスワードを認証するクラス

<?php

class Employee {
    const AUTH_SUCCESS = 1;
    const AUTH_NOTFOUND_USER= 2;
    const AUTH_INACTIVE_USER= 3;
    const AUTH_UNMATCH_PASS = 4;
    const AUTH_ERROR = 9;
    
    /**
     * 認証をする
    */
    public function checkAuth($code,$password){
        
	$db =  ←DB2接続処理
        // 認証
        $sql="select"
                ." code,rtrim(name) as name ,del"
                ." ,(case when decrypt_char(pwd)=? then 1 else 0 end) as auth_flag"
                ." from empl"
                ." where code = ?";
        $result = db2_prepare($db,$sql);
        db2_bind_param($result ,1 ,"password",DB2_PARAM_IN);
        db2_bind_param($result ,2 ,"code",DB2_PARAM_IN);
        if(!db2_execute($result)){
	    $flag =  self::AUTH_ERROR;    //エラー
	    return $flag;
	}
        $row = db2_fetch_assoc($result);
        //認証判定
        if ($row) {
            if ($row["del"] == "D"){
                $flag =  self::AUTH_INACTIVE_USER;  //廃止ユーザ
            }elseif ($row["auth_flag"] == 0){
                $flag = self::AUTH_UNMATCH_PASS;    //パスワード不一致
            }else{
                $flag =  self::AUTH_SUCCESS;    //成功
            }
        }else{
            $flag =  self::AUTH_NOTFOUND_USER;  //ユーザーなし
        }
        return $flag;
    }
}
?>
Zend_Auth_Adapterの実装

”Zend_Auth_Adapter”では”authenticate”メソッドを実装して、”Zend_Auth_Result”のインスタンスを返して、例外に”Zend_Auth_Exception”をスローする必要があります。前述のクラスのチェックメソッド(checkAuth)を使って、こんな感じで実装します。

<?php 
require_once 'Employee.php';
require_once 'Zend/Auth/Adapter/Interface.php';
require_once 'Zend/Auth/Adapter/Exception.php';
require_once 'Zend/Auth/Result.php';

class EmployeeAuthAdapter implements Zend_Auth_Adapter_Interface
{
    private $id;
    private $password;
    private $name;  
    public function __construct($id, $password){
        $this->id = $id;
        $this->password = $password;
    }  
    /**
     * 認証
    */
    public function authenticate() {
        $id = $this->id;
        $password = $this->password;
        $code = null;
        $message = "";
    try {
        //社員インスタンス
        $empl = new Employee();
        $ret = $empl->checkAuth($id,$password);
        $msgCode = $ret;
        //結果
        switch ($msgCode) {
        case Employee::AUTH_SUCCESS:
             $code = Zend_Auth_Result::SUCCESS;
             $message =  "認証OK";
             break;
        case Employee::AUTH_NOTFOUND_USER:
             $code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
             $message =  "ユーザーが見つかりません";
             break;
        case Employee::AUTH_INACTIVE_USER:
             $code = Zend_Auth_Result::FAILURE_UNCATEGORIZED;
             $message =  "ユーザーが廃止されてます";
             break;
        case Employee::AUTH_UNMATCH_PASS:
             $code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
             $message =  "パスワードが違います";
             break;
        default:
             $code = Zend_Auth_Result::FAILURE_UNCATEGORIZED;
             $message =  "その他のエラー";
             break;
        }
    } catch (Exception $e) {
	throw new Zend_Auth_Exception("予期せぬ例外で認証エラー");
    }
    $result = new Zend_Auth_Result($code,$id,array($message));
    return $result;
    }  
}
?>
AuthAdapterの使用

実際に使用する時は、先ほど実装した”authenticate”メソッドで、Zend_Auth_Resultを取得して、”isValid”メソッドで認証します。trueが返れば成功です。認証結果のメッセージは”getMessages”で、メッセージのリストが返されます。

<?php
    require_once 'EmployeeAuthAdapter.php';
    //認証アダプタ
    $adapter = new EmployeeAuthAdapter($id,$password,$autologin);
    //認証
    $ret = $adapter->authenticate();
    if($ret->isValid()){
         //成功の処理
    }else{
         //失敗の処理
         $message = $ret->getMessages();
         echo $message[0] ;
    }
?>

認証画面は、こんな感じに出来ました。

暗黙スキーマの挙動の違い

PCからお手軽に、既存のIBM i(AS/400)のプログラムを呼び出す方法に、SQLのCALLを投げる方法があります。こんな感じで
■PC系の文法

CALL スキーマ名.プログラム名 ('引数','引数2')

AS/400の対話式SQL

CALL スキーマ名/プログラム名 ('引数','引数2')

通常自分は、ユーザーによって実行ライブラリが異なる可能性があるので、ライブラリ名(スキーマ名)を指定しません。スキーマ名を変数にしても良いのですが、AS/400の伝統的に暗黙のオープンというのがあります。暗黙オープンの方法としては...

  1. ユーザージョブの”ライブラリーリスト”に入れる。
  2. ”set schema ライブラリ名”をする。

が、考えられます。前者は、本番運用向きとは思いますが、開発の場合は環境毎にユーザーが変わるので、自分は後者の「set schema」を使っています。
この”暗黙のスキーマ”なのですが、PHPDB2関数で、微妙にAS/400とPCで挙動の違いが有ったので、メモをしておきます。

AS/400(Zend Core for i5 2.6.1)の場合は、”set schema”でスキーマを指定すれば、暗黙でプログラムをcall出来ます。しかし開発用PC(Zend Server CE 4.0)から発行されたSQLの場合には、次の様なメッセージが返されました。

call hoge ('fuga') SQL0204N  "ユーザ名.hoge" は未定義の名前です。  SQLSTATE=42704

PHPDB2関数かDB2 Connectなのか分かりませんが、暗黙のスキーマが見つからない場合は、自動でユーザー名を明示的スキーマに置き換えます。(間違って存在していて勝手にプログラムが動かれても困りますが...。)
今回は対応方法として、AS/400のプログラムをストアドプロシージャ定義する事にしました。方法は以下の通りです。

    • OPMプログラムならばILE化する。(OPMだとストアド情報の保管・復元が出来ないため)
    • ”create procedure”で、プログラムをストアド定義する。

■ストアド定義SQLの例(※CLプログラムで5バイト文字列の引数を1つ取る場合)

CREATE PROCEDURE スキーマ名/プロシージャ名(IN 引数名 CHAR (5 )) LANGUAGE CL
NOT DETERMINISTIC CONTAINS SQL EXTERNAL NAME ライブラリ名/プログラム名
PARAMETER STYLE GENERAL       
    • 実行時に”set path スキーマ名”で関数パスを指定して、プロシージャ名をcallで呼びだす。

OPMをILE化するのは、SAVLIBやRSTLIBでストアド定義の情報が反映されないからです。検証してわかったのですが、プログラムのリネームや削除、ライブラリのリネームをしてもストアド情報と同期はされません。プログラムをSAVOBJ,RSTOBJしても同様に、ストアド情報は同期されませんでした。但し、ライブラリを削除した時だけは、ストアド情報も消えるようです。ライブラリを保管→ライブラリ削除→ライブラリ復元だと、ストアド情報も同期された状態で、復元しました。この事から、ILEオブジェクトの何処かに、ストアドに関するメタ情報を持っていると思うのですが、何処にあるか見つける事が出来ませんでした。(DSPPGMなどには無かった)
※追記:その後、DMPOBJコマンドでメタ情報を確認出来ました。SQL文が丸ごと残ってます。
ちなみに、OPMでストアド定義すると、プロシージャは作成されますが、その旨の警告メッセージが出力されました。
■注意書き(※DB2 Universal Database for iSeries SQL 解説書より)

*PGM オブジェクトが保管された後、このシステムや別のシステムに復元すると、カタログはそれらの属性を使用して自動的に更新されます。
外部プロシージャーの場合は、次の制約の範囲内で属性を保管することができます。
・ 外部プログラム・ライブラリーは、QSYS であってはなりません。
・ 外部プログラムは、CREATE PROCEDURE ステートメントの発行時に存在していなければなりません。
・ 外部プログラムは、ILE *PGM オブジェクトか*SRVPGM オブジェクトにする必要があります。
オブジェクトを更新できない場合でも、それにかかわらず、プロシージャーは作成されます。

これでプロシージャ名を呼び出せば、AS/400でもPCでも暗黙的にプログラムを呼び出す事が出来ます。
但しこの場合は、プログラム名の呼出と違って、AS/400でも”set path”で関数パスを指定する必要があります。ちなみに、ジョブのライブラリーリストに入っていれば、”set path”は不要です。本番運用ならばライブラリーリストでやるのが、一番楽チンかもしれませんネ。

ストアドプロシージャ定義の一覧を確認するには、次のSQLを投げると確認出来ます。

 select * from sysroutines where specific_schema = 'スキーマ名'

Haskell読書会4th@ShizuDev

早いものでShizuDev主催のHaskell読書会も第四回を迎える事が出来ました。今回はin三島という事で、初の東部開催です。段取りなどは、東部の方に、御協力を頂いた事に感謝しております。場所は三島の商工会議所で、非常に設備も良いところで、ぜひまた使わせて頂きたいと思いました。今回使用した部屋以外にも、ディスカッションやロールプレイングに使えそうな部屋もあり、少数名でディスカッション形式の勉強会も面白いなと思いました。

スピーカーは、静岡IT Proの代表でもある、id:ftnkさんで、第五章のテーマは「リスト内包表記」についてです。締めはシーザー暗号のクラックまでと、一つのテーマなのですが、演習問題は意外と骨の有る章でした。
今回の勉強会で、今までと少し違ったスタイルだったのは、課題図書を読み上げた所までで、出来る演習問題は、こなしてしまうという手法です。過去の勉強会は、最後に纏めて演習問題だったのですが、記憶に焼き付いて間もなく演習問題をする方が、効率も良く、些細な疑問も処理し易かったように思えます。自分の時は、「このスタイルでイコウ」と思いました。

個人的にはループ処理のガチガチ頭の人間からすると、リスト内包表記の妙味というか、そう言ったものを感じ取れました。
例えば、サイコロの出目のパターンをRPGでループ処理した時、
RPGの場合

%subarr(xs:1) ='123456';
%subarr(ys:1) ='123456';
i = 0;
for ix1 = 1 to 6 ;
    for ix2 = 1 to 6 ;
         i+=1;
         ptn(i).x = xs(ix1);
         ptn(i).y = ys(ix2);
    endfor;
endfor;

は、こんな感じで、手続き型言語で見る典型的な例かと思います。次にHaskellのリスト内包表記
Haskellの場合

[(x,y)|x<-[1..6],y<-[1..6]]

ループの入れ子が、ワンライナーで書けてしまうところが、レガシー人間からするとただただ羨ましい。(最初にforeachを見た時も少し感動したぐらいですから)
このリスト内包表記の入れ子は、カンマ区切りでさらに拡張できます。たとえば3つの入れ子ならば、

[(x,y,z)|x<-xs,y<-ys,z<-zs]

となります。さらに抽出条件まで付けてしまう事が出来ます。例えば,x,y,zの合計が20以上のみリストとするみたいな場合

[(x,y,z) | x<-xs,y<-ys,z<-zs,sum([x,y,z]) >=20]
or
[(x,y,z) | x<-xs,y<-ys,z<-zs,(x+y+z) >=20]

実に不思議だと感じたのは、ただカンマ区切りにしただけで、何故にココまで高機能なのか?もちろん実装がそうなるように工夫してあるといえばそうなのだけど、演習問題でリスト内包表記の入れ子が出てきた時に、こう感じました。「これはある意味シンタックスシュガーなのでは?」と...。

前述の以下の表記は、
■例1

[(x,y)|x<-[1..6],y<-[1..6]]
や
[(x,y,z)|x<-[1..6],y<-[1..6],z<-[1..6]]

こう書く事も出来る
■例2

concat [[(x,y)|y<-[1..6]]|x<-[1..6]]
や
concat ( concat [[[(x,y,z)|z<-[1..6]]|y<-[1..6]]|x<-[1..6]] )

リスト内包表記を1つのシンタックスとして捉えた時、通常入れ子を表現する場合、実は例2の方がごく自然な形で、ただ入れ子にすればする程、concatが必要になり、リスト表現としても分かりづらくなる、そこで工夫されたのが、例1の様なシンタックスシュガーなのかと、勝手に理解しました。普通に考えて、例1が使えれば例2は複雑なだけで、通常使う場面がないなと思うほど良く出来ていて、あえてソレを解らせるための演習問題?と考えると奥が深いなと思い知らされました。
色々な意味で、さらにHaskellの世界に引き込まれていく予感が...。

今回のおやつは、メンバー中最年少高校生のSupaki君が、かの遠州銘菓”たこまん”で買ってきてくれました。”たこまん”の名前だけはよく見るのですが、食べるのは初めてで、ブッセ風の美味しいオヤツをありがとう。

■おやつ