スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門第26回(引数1個の関数の連鎖)

今回のお題は「引数1個の関数の連鎖」です。
 
宿題の前にPerson型の定義を再掲しておきます。
type Person =
    { name   : string ;
      age    : int ;
      height : float}
      
(宿題)
 
上のPerson型を使って、string型の仮引数 strName とPerson list 型の仮引数 pLstをとり、pLstの中でnameがstrNameと同じ要素があれば、その内の最初の要素のageをSome (age)で、なければNoneを返す関数tryFindByNameを定義してください。
始まりは次のようになります。
let tryFindByName (strName : string) (pLst : Person list) =
 
(答えの例)
 
let tryFindByName (strName : string) (pLst : Person list) =
    let p = List.tryFind (fun (x : Person) -> x.name = strName) pLst
    match p with
    | Some (x) -> Some(x.age)
    | None     -> None    
 
実行例(personLstは前回定義したものを使っています。)
 
> tryFindByName "Mike" personLst;;
val it : int option = Some 77
 
> tryFindByName "Kate" personLst;;
val it : int option = None
 
さて今回の話題です。
プログラムを書いていて、次のように、ある値に関数fを適用して、その返り値にgを適用して、その返り値に    hを適用して、というように引数1個の関数を返り値に連鎖的に適用していく場面がよくあります。コードで書くと次のようになるかと思います。(最初の引数をseedとします。)
let a = f seed
let b = g a
let c = h b
 
途中経過を納めるためだけの識別子a,bを除いて一度に書くと次のようになります。
let c = h (g (f seed))
関数適用の連鎖が長くなると上の書き方では、見にくいので、F#ではpipe-forward演算子というものが準備されていて、これを使うと上は次のように書き直せます。
 
let c = seed 
        |> f 
        |> g 
        |> h
 
一番最初の材料(この場合はseed)がベルトコンベアーに載せられて、f ,g ,h の適用を次々受けていっているイメージです。
 
引数が2個以上の関数については、関数の部分適用をして、引数が1個の関数にしてから、この演算子を使います。
 

 
 [1;2;3;4;5;6;7]
 |> List.filter (fun x -> x % 2 = 0)
 |> List.fold (+) 0
 
上の結果が分かりますでしょうか。答えは12です。
 
ちなみに、逆方向のpipe-backward演算子というものもあり
seed |> f |> g |> h が
h <| g <| f <| seed と書けます。
 
また次々関数を適用していく場合の、関数だけを合成することもできます。
 
例えばfを適用して、gを適用して、hを適用する関数を一度に書くと
f >> g >> h と書けます。
すなわち
seed |> f |> g |> hは
seed |> (f >> g >> h)とも (f >> g >> h) seedとも書くことができるわけです。
 
また、これも逆方向が準備されていて、(f >> g >> h)は (h << g << f)と書けます。
 
これらは中置演算子ですので、()をつければ関数扱いになるはずです、調べてみます。
 
> (|>);;
val it : ('a -> ('a -> 'b) -> 'b) = <fun:it@3-3>
 
> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@4-4>
 
> (<|);;
val it : (('a -> 'b) -> 'a -> 'b) = <fun:it@5-5>
 
> (<<);;
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:it@6-6>
 
ということで、
a |> f は (|>) a f
f >> g は (>>) f g
f <| a は (<|) f a
f << g は (<<) f g と書けます。
 

 
let cfrl (f:int -> int) (g:int ->int) op :int-> int=
    op f g  
//最後のint->intは関数全体にかかっているので注意
let pacfrl = cfrl (fun x -> x + 1) (fun x -> 2*x)
とします。
(pacfrl (>>)) 2 と
(pacfrl (<<)) 2の値が分かりますでしょうか。
 
pacfrlはcfrlに2個の関数を部分適用したものになります。よって
 
上側は2に (fun x -> x + 1)を適用してから(fun x -> 2*x )を適用するので6
下側は2に (fun x -> 2*x)を適用してから(fun x -> x + 1 )を適用するので5となります。
 
宿題
 
let lst : (int -> int) list = [(fun x-> x + 1);(fun x -> 3 * x);(fun x -> x + 2) ]
let f = List.fold (>>) (fun x -> x) lst 
 
としたときfは何を表すでしょうか。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

引数が2個の関数

||> とかがあります。
let inline (||>) (x1,x2) f = f x1 x2
のように定義されています。
この場合、2個の引数がタプルでパイプすることになります。

RE 引数が2個の関数

知りませんでした。情報ありがとうございます。調べてみたら |||> までありました。
プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。