LoginSignup
8
5

More than 5 years have passed since last update.

map関数

Last updated at Posted at 2016-10-20

map関数

初めに

  • Haskellを学ぶ際には、map関数を避けて通れない、ということで、自分自身混乱しかけたので、まとめてみました。
  • 値と関数を同一視すること。そのためには、型を意識することが大事です。

準備

https://ja.wikipedia.org/wiki/Haskell

変数に束縛するのが定数であるか関数であるかにかかわらず、「変数 = 値」という一貫した形でも定義できる。

ということで、関数も値も変数と呼ぶ。

関数型

--関数も変数
--[引数の型(型変数)] -> [返り値の型]の形。

--1変数引数の場合
Prelude> :t fst
fst :: (a, b) -> a
                        {-
 ↑      ↑  
変数   型変数 
-}

Prelude> :t head
head :: [a] -> a
                        {-
 ↑       ↑  
変数    型変数 
-}
Prelude> :t tail
tail :: [a] -> [a]
                        {-
 ↑      ↑  
変数   型変数 
-}
  • 1変数関数の場合
Prelude> head [1,2,3,4]
1
Prelude> :t head
head :: [a] -> a

head関数を2つの側面から見る。(なので、関数も変数は見方が違うだけのもの)
 1. リストを引数にとり、戻り値を返す関数
 2. [a] -> a型の変数

多変数関数の場合を考えると、より鮮明になる。

  • 2変数関数の場合
--takeはIntとリストを引数に取り、先頭から指定された数の要素を取り出すリストを返す2変数関数。
Prelude> take 1 [1,2,3]
[1]

Prelude> :t take
take :: Int -> [a] -> [a]
{-
take :: Int -> ([a] -> [a]) のこと。
-}

take関数を3つの側面から見ることができる。(なので、関数も変数は見方が違うだけのもの)
 1. Int と [a]を引数にとり、[a]を返す関数
 2. Intを引数に取り、[a] -> [a]型の変数を返す関数
 3. Int -> [a] -> [a]型の変数

2番目のとらえ方を採用すると、(take 1)関数は、
 1. [a]を引数に取り、[a]を返す関数
 2. [a] -> [a] 型の変数

の二つの見方ができる。

Prelude> :t take 1
take 1 :: [a] -> [a]

map関数について

定義

map関数は、1変数関数と、リストを受け取り、その関数をリスト内のすべての要素に対して、作用させて、新規のリストを戻り値とする。

1

Prelude> map (+2) [2,3,4,5,6]
[4,5,6,7,8]

というような使用例。

C#を知っているなら、LINQのSelect関数と同じ。

using System.Linq;

public class Hello{
    public static void Main(){

        //SelectがHaskellのmap関数に相当。
        Enumerable.Range(2,5).Select(c =>c + 2)
        .ToList()
        .ForEach(c=>System.Console.WriteLine(c));

    }
}

もしくは、pythonのリスト内包表記と同等。

print ([x+2 for x in range(2,7)])

説明

Prelude> :t map
map :: (a -> b) -> [a] -> [b]

map関数は3つの側面から見ることができる。
 1. (a -> b)型の変数 と [a]を引数にとり、[b]を返す関数
 2. (a -> b)型の変数を引数に取り、[a] -> [b]型の変数を返す関数
 3. (a -> b) -> [a] -> [b]型の変数

2番目の考え方が特に大事。

冗長だが、2項演算子(+)を用いるので、同様の説明をする。

Prelude> :t (+)
(+) :: Num a => a -> a -> a

+演算子は3つの側面から見ることができる。
 1. a と aを引数にとり、aを返す関数
 2. a型の変数を引数に取り、 a -> a型の変数を返す関数
 3. a -> a -> a型の変数

2番目の観点で+演算子を見ると、

Prelude> :t (+2)
(+2) :: Num a => a -> a

ということで、(+2)をa -> a型の変数とみることができる。

map関数の挙動としては、

Prelude> map (+2) [2,3,4,5,6]
[4,5,6,7,8]
-- a -> a型の変数である(+2)とリストを引数に取っている
-- !! 1 は、リストから、1番目の要素を取ってくる演算子
Prelude> map (+2) [2,3,4,5,6] !! 1
5

map関数の応用

第一引数に、2変数関数を持ってきたときはどうなるのか?

f :: a -> b -> c

これは、a を引数として、b -> c型の変数を返す関数とみることもできる。
map (+) [2,3,4,5,6] !! 1は、(+3)、つまり、1変数関数となる。

(+3)自体はコンソールにprintできないので、以下を実行してみる。

--  map (+) [2,3,4,5,6] !! 1は、a -> a型の引数(1変数関数)
Prelude> :t (map (+) [2,3,4,5,6] !! 1)

--map関数にa -> a型の変数(+3) と[a]を引数に取る。
(map (+) [2,3,4,5,6] !! 1) :: Num a => a -> a
Prelude> map (map (+) [2,3,4,5,6] !! 1) [2,3,4,5,6]
[5,6,7,8,9]

ということで、問題ない。

ラムダ式

ラムダ式も、関数と変数を同一視すれば理解は容易い。

-- (\x -> x + 3)は、 a->a型の変数
Prelude> :t \x -> x + 3
\x -> x + 3 :: Num a => a -> a
--map関数にa -> a型の変数(\x -> x + 3) と[a]を引数に取る。
Prelude> map (\x -> x + 3) [2,3,4,5,6]
[5,6,7,8,9]

次やること

次はfmapをまとめたい。

参考

すごいHaskellたのしく学ぼう!
https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86-Miran-Lipova%C4%8Da/dp/4274068854


  1. Haskellの内包表記でも書けますが、今回はmap関数を説明するために簡単な例を用いています。 

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5