Haskellのカリー化の話。
・curry :: ((a, b) -> c) -> a -> b -> c
という関数について、
((a, b) -> c)をa -> b -> cとするのはカリー化といえるか?
ということの考察。
Haskellで言うカリー化と言われているのは、
(\x y = x + y) => (\x -> (\y -> x + y))
という変換であり、
Haskellのcurry関数は、
(\(x,y) -> x + y) => (\x -> (\y -> x + y))
という変換をしているのであり、curry関数は「Haskellのカリー化」と言えない。
しかし、直積の集合を取る関数 f:(A x B)->Cを、g:A->(B->C)と捉えるならば、タプルを取る関数は直積集合を取る関数と捉えられ、先のcurry関数の変換ほうがむしろカリー化として妥当じゃないではないか?ということ。
Haskellのcurryとuncurry関数をcurryなのか?というとすごい微妙だと思う。A x B -> Cという関数A -> B -> Cとするのがカリー化だと思うが、A x Bという直積をタプルと捉えようと思えば思えるけど、タプルを取る1引数関数を変換しただけともとれる
2013-08-22 02:10:26Haskellは多変数関数を、複数の変数を内包したタプルを取る関数と捉えるならば、curry関数はcurryと言える。
2013-08-22 02:18:31Haskellのタプルを取る関数を多変数関数とすれば、たとえば、(\x y -> x + y)というのは多変数関数ではないよね。引数がタプルじゃないもん。ただの(\x -> (\y -> x + y))のシンタックスシュガーとも言えるんじゃないか?
2013-08-22 02:20:07もしHaskellのcurry関数の変換の方をカリー化と捉えるならば、
(\x y -> x + y) => (\x -> (\y -> x + y))
というのは、いったい何者なのか?
(\x y -> x + y)
というのは、実は2引数関数ではなくて、
ただの
(\x -> (\y -> x + y))
へのシンタックスシュガーではないかということ。
つまりHaskellの関数ははそもそもカリー化されているのではなく、多引数関数を作ることが出来ないようになっているということ。
だからHaskellは、むしろタプル無しで複数の引数を持つ関数は作ることが出来ないといことか。カリー化しちゃうからねー。
2013-08-22 02:41:25カリー化されてない関数が部分適用できるのであって、カリー化されていると部分適用はできないよな。1引数関数だから部分なんて無い。
2013-08-22 02:46:04基本的には const x = \y -> x も const x y = x も記法の違いと考えてる。実装は不知火。
2013-08-22 12:33:17Haskellはそもそも多引数を取る関数が無いので、すべての関数がカリー化されてるという表現は厳密には正しくないと思ってる。
2013-08-22 12:34:52もともとカリー化もクソもないので、部分適用と言う語も適切ではないという事になっちゃうんだけど、必要であれば便宜的に使うかなぁ。
2013-08-22 12:37:17@its_out_of_tune 僕もある程度そう思うんだけど、部分適用は、たとえば、f(x,y,z)があったとすると、変数の一部を束縛した関数、f'(y) = f(x =Y, y, z=Z)と返す訳で、その過程で必ずしもカリー化されているか?といえそうでは無い気がする。
2013-08-22 13:36:40@nobkz 難しいな…f'(y)=f(x=X, y)と、curry(f)(X) は外延的に等価なだけであって、部分適用とカリー化に直接的な関係は無いだけとゆー事かしら…
2013-08-22 14:11:28@its_out_of_tune 多分そう言うことだと思う。こう考えると意外と部分適用とカリー化がややこしいことになってると思う。けれども、実際にはある程度混同してもそうそう困ること無いんじゃない?
2013-08-22 14:16:12@nobkz ですねー。大体Haskellで「カリー化されてる」と言えば高階になってるという意味合いですし、部分適用といえば高階関数に引数を与える事なので、よくある「部分適用の事をカリー化と呼ぶ」レベルの間違いでなければさしたる問題は無いと思いまふー。
2013-08-22 14:57:52