Piz&Yuminaのプログラミング勉強ノート

最近はプログラミングから脱線気味・・・

目次

Blog 利用状況

ニュース






未だにわんくまのメールが使えないので、連絡は↓にお願いします。 piz_yumina@hotmail.com


Piz&Yumina
名前:Piz&Yumina(ぴずあんどゆみな)
生年月日:1990年02月13日(平成02年02月13日)
年齢:20
性別:♂
血液型:B
星座:水瓶座
趣味:(学習系)数学 英語 (消費系)アニメ ギャルゲー エロゲー (開発系)プログラミング (創作系)小説 詩 短歌 絵 (執筆系)プログラミング・数学分野の記事執筆
TOEIC:685点(2009/09)
簿記:-(学習中)



書庫

日記カテゴリ

CREAプロジェクト

pixiv

雑記ブログ

[F#]関数の部分適用

カリー化currying)とは、n個の引数を取る1つの関数を、1つの引数を取るn個の関数の連鎖に変換する操作のことです。

数式を使って書くと、関数

f:(X1×X2×……Xn)Y

が与えられた時、カリー化関数curried function

curry(f):X1(X2(……→Xn……))

を得る操作をカリー化と言います。この場合、カリー化関数curry(f)1つの引数x1X1を取り関数X2(X3(……→Xn……))を返す関数です。返された関数X2(X3(……→Xn……))1つの引数x2X2を取り関数X3(X4(……→Xn……))を返す関数です。このような連鎖がn回続くことになります。

 

F#の関数は通常自動的にカリー化されます。

例えば、2つの引数を取ってその和を返す関数は次のようになります。

let summation1 a b = a + b

これは記法上2個の引数を取る関数に見えますが、F#では自動的にカリー化されるので、以下のような関数を返す関数と同じになります。

let summation2 a =

    fun b -> a + b

実際、2つの関数をF#インタープリタで定義してみると全く同じ結果が返ってきます。

clip_image002

また、これは括弧がない点を除いて、上記の数式によるカリー化関数の表現とも同じであることが分かります。

 

関数summation1で第1引数だけを渡せば、第1引数が部分適用されたpartially applied)関数が返されます。

let x = 4

let y1 = 6

let y2 = 8

let summation1 a b = a + b

let summation2 = summation1 x

let result1 = summation2 y1

let result2 = summation2 y2

printfn "%d + %d = %d" x y1 result1

printfn "%d + %d = %d" x y2 result2

clip_image004

 

F#の関数は全て自動的にカリー化されますが、場合によってはカリー化を抑止したいことがあります。つまり、関数を複数個の引数を取る1つの関数として定義したい場合があります。

その場合は、引数全体を括弧で囲みそれぞれの引数をカンマで区切ります。そうすると自動的にカリー化されることはありません。

例えば、先の関数summation1を自動的にカリー化させないようにするには、次のようにします。

let summation (a, b) = a + b

clip_image006

関数の定義後にF#インタープリタによって返された結果が先程とは異なっており、「int * int -> int」と2つのint型の引数を取ってint型の値を返す関数が定義されたことが分かります。

この関数を呼び出すときは、2つの引数を同時に渡さなければならないのは勿論ですが、関数を定義した時と同じように引数全体を括弧で囲みそれぞれの引数をカンマで区切らなければなりません。さもないと、エラーが発生します。具体的には以下のように書きます。

printfn "result = %d" (summation (1, 2))

clip_image008

引数全体を括弧で囲みそれぞれの引数をカンマで区切らないと、「summation 1」は関数ではなく、引数を適用できないと怒られます。

1つしか引数を渡さないと、型が違うと怒られます。

投稿日時 : 2009年1月13日 0:10

コメントを追加

# re: [F#]関数の部分適用 2009/01/13 14:30 いげ太

tupled form を curried form に変型する FuncConvert.FuncFromTupled メソッド、
curried form を tupled form に変型する FastFunc{N}.Adapt メソッド
('{N}' は [2-5] の数字に置き換え)なんてのもありますね。

open System

// val tupled_fun : (string -> string -> IFormatProvider -> DateTime)
let tupled_fun : _ -> _ -> IFormatProvider -> _ =
FuncConvert.FuncFromTupled (DateTime.ParseExact : _ * _ * _ -> _)

// val curried_fun :
// OptimizedClosures.FastFunc3<string,string,IFormatProvider,DateTime>
let curried_fun =
OptimizedClosures.FastFunc3<_, _, IFormatProvider, _>.Adapt tupled_fun

# re: [F#]関数の部分適用 2009/01/13 14:41 いげ太

うわっ、すいません。名前が逆だ(汗

open System

// val curried_fun : (string -> string -> IFormatProvider -> DateTime)
let curried_fun : _ -> _ -> IFormatProvider -> _ =
FuncConvert.FuncFromTupled (DateTime.ParseExact : _ * _ * _ -> _)

// val tupled_fun :
// OptimizedClosures.FastFunc3<string,string,IFormatProvider,DateTime>
let tupled_fun =
OptimizedClosures.FastFunc3<_, _, IFormatProvider, _>.Adapt curried_fun

# re: [F#]関数の部分適用 2009/01/14 2:33 Piz&Yumina

なるほど、自分で変換することも簡単にできるのですね。
まだF#については超初心者レベルなので勉強になります。

タイトル  
名前  
URL
コメント