3引数のflip

久しぶりに時間があいたので Haskell をやってみよう,と思ったらこんなのを見つけた。

haskellのある暮らし - 頭の体操:3引数flip

f :: a -> b -> c -> d なる関数 f があったとして,

 flip31 f a c b = f a b c

みたいに引数の順番を入れ替える関数をポイントフリースタイルで定義せよ,ってのが今回の指令。ただし f は残っても良い。
さっそくやってみるさー。


といってもパッと答えがひらめいたりはしないので地道に変換する。

 flip31 f a c b = f a b c
             -->  flip (f a) c b
             -->  (flip.f) a c b

となって,引数を消すと

 flip31 f = flip.f

つぎ。

 flip32 f b a c = f a b c
             -->  (f a b) c
             -->  (flip f b a) c
             -->  (flip f) b a c

結局

 flip32 f = flip f

あー,つまり flip の引数が特殊な場合ってことか。


残りの3つは結果だけ書く。

 flip33 f = flip.(flip f)
 
 flip34 f = flip (flip.f)
 
 flip35 f = flip (flip.(flip f))

これでOKのはず。
もと記事にある関数でチェックしてみる。

 *Main> check
 [True,True,True,True,True]

OKのようだ。


もう少し,見た目にわかりやすいようなチェックをしてみよう。

 *Main> let f a b c = a:b:c:[]
 *Main> flip31 f 'a' 'c' 'b'
 "abc"
 *Main> flip32 f 'b' 'a' 'c'
 "abc"
 *Main> flip33 f 'b' 'c' 'a'
 "abc"
 *Main> flip34 f 'c' 'a' 'b'
 "abc"
 *Main> flip35 f 'c' 'b' 'a'
 "abc"

OK。
けど,せめて関数の型をちゃんとかいておかないとさっぱりわかんないよな,これ。



追記:
さらに f も無くしてみる。

 flip31' :: (a -> b -> c -> d) -> a -> c -> b -> d
 flip31' = (flip.)
 
 flip32' :: (a -> b -> c -> d) -> b -> a -> c -> d
 flip32' = flip
 
 flip33' :: (a -> b -> c -> d) -> b -> c -> a -> d
 flip33' = (flip.).flip
 
 flip34' :: (a -> b -> c -> d) -> c -> a -> b -> d
 flip34' = flip.(flip.)
 
 flip35' :: (a -> b -> c -> d) -> c -> b -> a -> d
 flip35' = flip.((flip.).flip)