「デリゲート」の版間の差分

編集の要約なし
 
(同じ利用者による、間の24版が非表示)
1行目: 1行目:
[[Category:Alice(名前空間)]]
{{Alert|この記事のより新しい版が[https://docs.wsoft.ws/products/alice/api/delegate/ WSOFTDocs]にあります。AliceScriptWikiでは、この記事はもう更新されません。||04}}[[Category:Alice(名前空間)]]
[[Category:基本]]
[[Category:基本]]
デリゲートは、AliceScriptにおける”匿名関数”のメカニズムです。デリゲートは匿名関数として、その場ですぐに実行したり、変数に代入したり、関数に引数として渡すことができます。
デリゲートは、AliceScriptにおける”匿名関数”のメカニズムです。デリゲートは匿名関数として、その場ですぐに実行したり、変数に代入したり、関数に引数として渡すことができます。


例えば、蔵書検索アプリケーションを作成することを考えてみましょう。この検索にはAND検索、OR検索、完全一致検索が用意されています。
例えば、蔵書検索アプリケーションを作成することを考えてみましょう。この検索の条件は、それと完全に一致する、それを含む、それを含まない、の3つが用意されています。いずれの場合も、Seartch()関数が行うことは基本的に同じです。つまり、なんらかの条件に基づいて一連の蔵書から項目を検索します。しかし、条件に基づいて検索するコードはそれぞれの条件によって異なります。
いずれの場合も、Seartch()関数が行うことは基本的に同じです。つまり、なんらかの条件に基づいて一連の蔵書から項目を検索します。しかし、条件に基づいて検索するコードはそれぞれの条件によって異なります。
 
そのような場面でデリゲートを使うと、変数のように値を変更することでプログラムの実行中に処理内容を切り替えることができます。Seartch関数に関連づけられているデリゲートを変更すればよいのです。


ソフトウェアには、この種の手法が半世紀にわたって使用されてきました。AliceScriptのデリゲートは、さらに思い通りのプログラミングを実現します。
ソフトウェアには、この種の手法が半世紀にわたって使用されてきました。AliceScriptのデリゲートは、さらに思い通りのプログラミングを実現します。


この記事では<code>delegate</code>キーワードとそれによって生成されるコード、<code>delegate</code>型に実装される機能を説明します。
デリゲートには次の特徴があります。
*デリゲートを使用すると、関数を引数として渡すことができます。
*デリゲートは、コールバック関数の仕組みを実現するのに使用できます。
*デリゲートは連結でき、たとえば、複数の関数を一度の呼び出しで実行することができます。
 
この記事では<code>delegate</code>キーワードまたはラムダ式によって提供される機能、<code>delegate</code>型に実装される機能を説明します。


[[Category:基本]][[Category:Alice(名前空間)]]
[[Category:基本]][[Category:Alice(名前空間)]]
28行目: 34行目:


==基本==
==基本==
デリゲート型は、<code>delegate</code>キーワードまたはその省略表現<code>_</code>と、そのデリゲートの実行に必要な引数を指定して宣言されます。
デリゲート型は、<code>delegate</code>キーワードと、そのデリゲートの実行に必要な引数を指定して宣言されます。


引数はかっこで囲み、各引数をコンマで区切ります。括弧内を空にすると、デリゲートは引数が不要なことを意味します。
引数はかっこで囲み、各引数をコンマで区切ります。括弧内を空にすると、デリゲートは引数が不要なことを意味します。
37行目: 43行目:
次の例にはデリゲートを生成し、それを<code>SayHello</code>として定義します。<code>SayHello</code>が呼び出されたとき、標準出力にHello,World!を書き込みます。
次の例にはデリゲートを生成し、それを<code>SayHello</code>として定義します。<code>SayHello</code>が呼び出されたとき、標準出力にHello,World!を書き込みます。


  var SayHello = _()
  var SayHello = delegate()
   {
   {
     print("Hello,World!");
     print("Hello,World!");
   }
   }
  SayHello();//出力例:Hello,World!
  SayHello();//出力例:Hello,World!
==ユーザー定義関数からの暗黙的な変換==
==ラムダ式==
ユーザー定義関数は、デリゲート型の変数へと暗黙的に変換できます。ユーザー定義関数を丸括弧なしで呼び出すと、それはその関数をデリゲート型に変換されたオペランドと認識されます。次に例を示します。
ラムダ式を用いてデリゲートを生成することもできます。[[式#ラムダ演算子|ラムダ演算子<code>=></code>]]は、引数指定部と式本体を分割する役割を持ちます。
 
ラムダ式には、次の2つの形式があります。
===式形式のラムダ===
式形式のラムダは、次の形です。
(input-parameters) => expression
式形式のラムダは、呼び出された時にその式の値を返します。
例えば、次のような関数が定義されていたとします。この関数は、与えられた数<code>num</code>を二乗した結果を返します。
function pow(number num)
  {
    return num ** 2;
  }
print(pow(2));//出力例:4
次の例は、この関数と等価な結果を返すデリゲートをラムダ式で定義する例です。
var pow = (number num) => num ** 2;
print(pow(2));//出力例:4
===ステートメント形式のラムダ===
ステートメント形式のラムダは次の形です。
(input-parameters) => { <sequence-of-statements> }
式形式のラムダとの違いは、ステートメント形式のラムダの本体が任意の数のステートメントで構成できる点と、<code>return</code>キーワードを使用することでのみ値を返すことができることです。次の例では、<code>x</code>を二乗した値を出力するデリゲートを<code>powoutput</code>という名前で宣言します。
var powoutput = (x) =>
  {
    var powed = x*x;
    print(x);
  };
powoutput(2);//出力例:4
==関数からの暗黙的な変換==
ほとんどのネイティブ関数とユーザー定義関数は、デリゲート型の変数へと暗黙的に変換できます。ユーザー定義関数を丸括弧なしで呼び出すと、それはその関数をデリゲート型に変換されたオペランドと認識されます。次に例を示します。
  function SayHello()
  function SayHello()
   {
   {
50行目: 83行目:
  var hello=SayHello;//helloは、DELEGATE型を表します
  var hello=SayHello;//helloは、DELEGATE型を表します
  hello();//出力:Hello,World
  hello();//出力:Hello,World
ただし、以下の属性を持っている関数を暗黙的に変換することはできません。
*言語構造
*関数の区切り文字の空白をサポート
*単一の引数のみ関数の区切り文字の空白をサポート
また、FunctionBase型を継承しない関数も、この機能をサポートしません。
関数の属性について詳しく知るには、[[関数#属性|関数]]の記事を参照してください。
==デリゲートの組み合わせ==
==デリゲートの組み合わせ==
デリゲート型は、複数のデリゲートを一つに結合することができます。組み合わされたデリゲートの各ステートメントは、順番に実行され、<code>foreach</code>文を使用して一つずつに分解することも可能です。上記の例ですでに<code>SayHello</code>を定義しましたから、もう一つ、<code>SayBonjur</code>デリゲートを定義し、それらを結合して実行する例を示します。
デリゲート型は、複数のデリゲートを一つに結合することができます。組み合わされたデリゲートの各ステートメントは、順番に実行され、<code>foreach</code>文を使用して一つずつに分解することも可能です。上記の例ですでに<code>SayHello</code>を定義しましたから、もう一つ、<code>SayBonjur</code>デリゲートを定義し、それらを結合して実行する例を示します。
 
  var SayBonjur = delegate()
  var SayBonjur = _()
   {
   {
     print(“Bonjur”);
     print(“Bonjur”);
61行目: 100行目:
  //出力例:Hello,World!
  //出力例:Hello,World!
  //    :Bonjur
  //    :Bonjur
==イベント駆動型プログラム==
==イベント駆動型プログラム==
イベント駆動型プログラムは例えば「キーボードが押下された」とか、「マウスが移動した」などの受動的なイベントの発生によってコードが実行されるプログラムです。AliceScriptでは、デリゲート型とその組み合わせによって実現できます。ここでは簡単なサンプルとして、1秒おきにHello,Worldを表示し続け、それをeキーが押下されたときに停止するプログラムを作成します。このコードでは非同期的に1秒前にHello,Worldを表示し続け、同時に同期的にキーの押下を待機し続け、なんらかのキーが押下されたときに<code>OnkeyDown</code>にキーの情報を渡して呼び出します。
イベント駆動型プログラムは例えば「キーボードが押下された」とか、「マウスが移動した」などの受動的なイベントの発生によってコードが実行されるプログラムです。AliceScriptでは、デリゲート型とその組み合わせによって実現できます。ここでは簡単なサンプルとして、1秒おきにHello,Worldを表示し続け、それをeキーが押下されたときに停止するプログラムを作成します。このコードでは非同期的に1秒前にHello,Worldを表示し続け、同時に同期的にキーの押下を待機し続け、なんらかのキーが押下されたときに<code>OnkeyDown</code>にキーの情報を渡して呼び出します。


  var OnKeyDown;
  var OnKeyDown;
  (_(){
  (()=>{
   //非同期に実行されるコード
   //非同期に実行されるコード
   while(true)
   while(true)
75行目: 113行目:
   
   
  //OnKeyDownに次のコードをイベントハンドラとして登録します
  //OnKeyDownに次のコードをイベントハンドラとして登録します
  OnKeyDown+=_(key)
  OnKeyDown+=(key)=>
   {
   {
     if(key==“e”)
     if(key==“e”)