49
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Higher Rank Type とは

Last updated at Posted at 2014-11-03

注意点

この文章は、自分が理解している範囲内でまとめたものなので、
正確性に欠ける、または、間違っている点を含んでいる可能性がありますのでご注意ください。

Polymorphic function

Haskell には polymorphic function と呼ばれるものがあり、例えば、 length 関数の型は、

length :: [a] -> Int

となっていて、任意の型 a について、実際の型を適用して具体化することができる。

-- GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
ghci> length ([2,3,4] :: [Int])
3
ghci> length ("string" :: [Char])
6

という具合。

forall

ここで、この polymorphic function をそのまま、関数の引数として渡したいとする。
単純に考えると型は以下のようになるが、

foo :: ([a] -> Int) -> Int
foo f = f [1,2,3] + f "string"

これはエラーになってしまう。

-- => Couldn't match type ‘a’ with ‘Char’

上記の定義では、 foo に渡す関数 f は polymorphic function ではなく「 a は任意の型のうち何かの型を適用して具体化したもの」、
つまり [Int] -> Int, [Char] -> Int などのどれか一つ、と解釈されてしまう。
そのため f [1, 2, 3]f "string" のように異なる型を適用することはできない。

では、どうすればよいのか。
そもそも、 polymorphic function の型:

length :: [a] -> Int

は、本来は、

length :: forall a. [a] -> Int

という具合に forall a. で全体を修飾したものを意味する。
同様に foo 関数の型は、

foo :: forall a . ([a] -> Int) -> Int

となる。
この forall a. は「任意の型 a に対して」という意味になるのだけれど、
上記の場合では forall a.foo 関数の型全体を修飾しているので、 foo 関数の定義内部では、型変数 a は何かひとつの型に定まったもの、として扱われてしまう。
このため、 polymorphic function のまま渡すことができない。
そこで、 polymorphic function のままの型で渡せるように、この forall a. が修飾している部分を、以下のように明示的に限定してやる必要がある。

{-# LANGUAGE RankNTypes #-}

foo' :: (forall a. [a] -> Int) -> Int
foo' f = f [1,2,3] + f "string"
ghci> foo' length
9

と、確かに polymorphic function が渡せるようになった。上記のような型を定義するには RankNTypes という GHC 拡張を使う必要がある点に注意。

Higher rank type

length 関数や foo 関数のように forall が型全体 ( 最外側 ) を修飾しているような型を rank-1 type と言い、
foo' 関数のように rank-1 type を引数に持つ関数の型を rank-2 type と言う。
一般的に rank-n type は rank-(n-1) type の型を引数に持つ、とのこと。

もう一度、 rank-1 type と rank-2 type の意味の違いを整理しておくと、

rank-1 type

foo :: forall a. (a -> Int) -> (Char, Bool)

とした時の、 foo の定義内での型変数 a は、任意の型のうち、何らかのひとつの型を表す。

rank-2 type

foo' :: (forall a. a -> Int) -> (Char, Bool)

とした時の、 foo' の定義内での型変数 a は、また具体化してないので、任意の型のうち、全ての型を (同時に) 表す。

参考にしたサイト

49
32
2

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
49
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?