関数

8.3 部分適用


なるほど、引数の一部を指定して、新しい関数を作っちゃう。
関数型プログラミング言語の真骨頂ともいうべきでしょうか。
これまで見たことのない手法です。
ですが、とても自然に馴染む考え方です。


何となくですが、今までにあまりよく理解せずに使っていました。

main = do cs <- getContents
          putStr $ unlines $ map (myFold 60) $ lines cs

myFold :: Int -> String -> String
myFold _ [] = []
myFold n cs = let (cs1, cs2) = splitAt n cs
              in
                cs1 ++ "\n" ++ myFold n cs2


分かりにくいですけど、myFold関数を部分適用しています。
こういう風にしておくと、
myFold60、myFold100、…という風な似たような関数を量産する必要がなくなります。
まぁ、考え方はあっていたわけですね。

二つ以上の引数をとる関数について

なるほど、Haskellには二つ以上引数をとる関数は存在しないんですね。
全ての関数は一つの引数しかとらない。


一見、なぜこんなことするのかなぁ、と思ってしまうところですけど、
関数は常に一つ、というのはとてもシンプルな規則ですよね。

myAdd :: Int -> Int -> Int
myAdd x y z = x + 10 * y + 100 * z


の場合、こんな感じで展開されます。

myAdd 1 2 3
(\y z -> 1 + 10 * y + 100 * z) 2 3
(\z -> 1 + 10 * 2 + 100 * z) 3
1 + 10 * 2 + 100 * 3
321


関数を引数一つに適用する度に新しい関数が作られていくわけですね。
GHCIで関数の型などを調べて遊んでみました。

Prelude> :t take 5
take 5 :: [a] -> [a]
Prelude> :t map (\x -> x)
map (\x -> x) :: [a] -> [a]


なるほど。確かに部分適用され、新しい関数が作られていますね。