言語指向型プログラミング

目次

概要

工事中

アクティブパターン

工事中

Active Decomposition

工事中

Active Discrimination

工事中

Partial Active Patterns

パーシャルアクティブパターンは、マッチの失敗を検出できるアクティブパターンです

パーシャルアクティブパターンを使うには、下記の必要があります。


では、さっそく具体的なサンプルを示します。

下記のサンプルは、ユーザーのアクセスレベルを調べます。

#light

type AccessLevel = High | Low

let (|AdminUser|_|) name =
    if name = "admin" then Some(High) else None
 

let (|GuestUser|_|) name =
    if name = "guest" then Some(Low) else None

let CheckAccessLevel n = 
    match n with
    | AdminUser n -> "Access Level High"
    | GuestUser n -> "Access Level Low"
    | _ -> "Access Deny"
    
let ret1 = CheckAccessLevel "admin"
printfn "admin  : %s" ret1
let ret2 = CheckAccessLevel "guest"
printfn "guest  : %s" ret2
let ret3 = CheckAccessLevel "yamada"
printfn "yamada : %s" ret3

実行結果

admin  : Access Level High
guest  : Access Level Low
yamada : Access Deny

書いてみたものの、ちょっと微妙なサンプルですねw 良いサンプルが思いついたらそれを掲載するようにします。
とりあえず、アクティブパターンの書き方はこのサンプルでもわかっていただけたかと思います。

Parameterized Active Patterns

工事中

ワークフロー

ワークフローはworkflowとbuilderからの2つからなります。

■workflow

workflowはcomputation expressionとも呼ばれます。

・workflow(computation expression)の書式

ident { cexpr }

※identには任意の名前をつけることができる。

workflow{
		   let  x = 2
		   let! y = 3
		   return x*y
        }

実はworkflowは継続的渡し処理の糖衣構文で、let! や returnはそれを実現するためのキーワードです。 先ほど定義されたworkflowは構文糖衣なしで下記のようになります。

workflow.Delay(fun () ->
    workflow.Let(2, (fun a ->
        workflow.Bind(3, fun b ->
            workflow.Return(a * b ) ) ) ) ) )

workflowは上記のように解釈されて実行されます。 糖衣構文でない例を見ると継続的に次へ渡しながら処理していくworkflowの特徴がよくわかるのではないでしょうか。

糖衣構文と糖衣なし構文の対応は下記になっています。

let!Bind
letLet
returnReturn

※他にもあるので、情報整理して追加します。。

■builder

workflowを構築するオブジェクトです。 letやlet!などの動作を定義します。 キーワードと糖衣なしのメソッドの対応は先ほどの表を参考にしてください。

#light

type Workflow<'a> = (unit -> 'a )

let runWorkflow (a:Workflow<'a>) = a()
let delay f = fun () -> runWorkflow ( f() )

type WorkflowBuilder() =
    // return
    member b.Return(x) =
        fun () -> x
    // let
    member b.Let(p,rest) : Workflow<'a> =
        rest p
    // let!
    member b.Bind(p,rest) : Workflow<'a> =
        rest p
    // delay
    member b.Delay(f) =
        delay f

では、ワークフローを実行してみましょう。

let workflow = new WorkflowBuilder()

let num = workflow { let  x = 2
                     let! y = 3
                     return x*y }
let ret = runWorkflow num
printfn "ret=%d" ret

sequence expression

sequence expressionはseqに関するworkflowです。

sequence expressionを利用することで、seq型をforやwhileなどの式から生成できます。

・sequence expressionの書式

seq { cexpr }
もっとも単純なサンプルを下記に示します。
> seq { for i in 0 .. 3 -> i*i };;
val it : seq = seq [0; 1; 4; 9]

リストや配列も同じような方法で生成できます。

・リスト

> [ for i in 0 .. 3 -> i*i ];;
val it : int list = [0; 1; 4; 9]

・配列

> [| for i in 0 .. 3 -> i*i |];;
val it : int array = [|0; 1; 4; 9|]

yield キーワード

yield キーワードを利用すると、コレクションに値を追加して、計算を継続することができます。

名簿ファイル(name_list.txt)から名前を読み込んで、表示するプログラムを作成してみます。 seq型のreader に名前を追加していき、最後Seq.iterで一つずつ出力します。

・name_list.txtの内容

山田
中村
田中
鈴木

・サンプルコード

#light
open System.IO

let reader = 
    seq { use reader = new StreamReader(File.OpenRead("name_list.txt"))
          while not reader.EndOfStream do
              yield reader.ReadLine() }
Seq.iter ( printfn "%s" ) reader

・出力

山田
中村
田中
鈴木
inserted by FC2 system