関数

From HaskellWiki
Jump to navigation Jump to search

数学的に言えば、関数というのはという集合のすべての値をという値の集合に関連付けるものです。関数が整数なら、整数の集合の中にある全ての要素を他の集合--この場合整数の2乗の集合に対応させます。Haskellの関数は以下の例で表されます。付属的に type specification がコンパイラ(や利用しようとするプログラマ)に関数の使い方のヒントを与えます。

Examples

square :: Int -> Int
square x = x * x

言い換えれば、関数というのは "入力" と "出力" を持っていて、入力からどのように出力を生成するかを記述したものといえます。関数は "適用する" ことができます。つまり単純に入力値を関数の引数として与えて、対応する出力値として受け取るということです。

Haskellの関数は "ファーストクラス" エンティティです。つまり

  • 名前が与えられる
  • ある式の値である
  • リストのメンバになれる
  • タプルの要素になれる
  • 関数の引数として与えられる
  • 関数の結果として返される

(Davieの "Introduction to Functional Programming Systems using Haskell."より引用)

map の例

ファーストクラス関数の威力を見られる例として、"map"関数を考えてみましょう。 map:

map :: (a -> b) -> [a] -> [b]
map f xs = [f x | x <- xs]

(これはHigher order functionであることを覚えていてください) この関数は2つの引数をとります:"f"という"a"から"b"へ写像する関数と、"a"のリスト"xs"です。返り値は"b"のリストで、これは"xs"の中のすべての要素に"f"を適用した結果のリストになります。したがって、map square [1,1,2,3,5,8][1,1,4,9,25,64]というリストを返します。"map"が返した”b”のリストが関数のリストにもなりえると気づくと、だんだん面白くなってきます。

あるデータ構造(たとえば"Set")があったとして、関数insert :: Int -> Set -> Setがあったとします。この関数は整数と集合を引数にとり、引数に与えた整数を引数に与えた集合に挿入してできた新しい集合を返します。そして、"mySet"と"myList"があるとして、それぞれ集合の中に集合やリストがあります。整数のリストを再帰的に要素1つづつ"myList"に挿入するような関数も書けますが、ファーストクラス関数を使えばもっと簡単に書けます。map insert myListという式を見てください。--この式が生成するリストの型はなんでしょうか?"insert"は"Int"と"Set"を引数にとりますが、"Int"しか与えられていませんので、結果のリストは集合を引数にとって、集合を返す関数のリストになっています。イメージとしては、コードmap insert [1,2,3]はリスト[(insert 1) (insert 2) (insert3)]を返します。

合成 / 畳み込みの例

HaskellではFunction composition演算子をサポートしています:

(.) :: (b -> c) -> (a ->b) -> (a->c)
(f . g) x = f (g x)

たとえば、((insert 1) . (insert 2) . (insert 3)) mySet<hask><hask> insert 1 (insert 2 (inesrt 3 mySet))と同じ意味です。すると、先の章の例を考えれば、もう一息のところまで来ています。--いま必要なのは自動的に合成演算子をmap insert myList<hask>のそれぞれの要素の間におくことです。Haskellではそれを可能にするコードがあります。それが"畳み込み(folding)"として知られているものです。 "fold"関数はいくつかの種類がありますが、基本的な概念としては同じです。関数とリストが与えられて、リストのすべての要素の"間に"関数を適応させてリストを"折り畳む"イメージです。簡単な二項演算子で考えてみるのが一番簡単ですが、実際使うときは他の関数でもなんら代わりはありません。たとえば<hask>foldr1 (+) [1,1,2,3,5]は結果として1+1+2+3+5という式を生成します。したがって12が返ってきます。集合の例ではfoldr1 (.) (map insert myList)は先程我々がほしがっていたものを与えてくれます。つまり、連続して”myList"に要素を挿入してくれるわけです。この式の型はどうなっているのでしょうか?答えはSet -> Setです。つまり集合を引数に取り、集合を返すわけです。--この例では返り値の集合は"myList"のすべての要素が挿入されたものになります。例を完成させると、

newSet = (foldr1 (.) (map insert myList)) mySet

は"newSet"を"mySet"に"myList"の要素が挿入されたものとして定義しています。

参考

Languages: ja