コード例から始めましょう。
foob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b
foob postProcess onNothin onJust mval =
postProcess val
where
val :: b
val = maybe onNothin onJust mval
このコードは、単純な Haskell 98 ではコンパイルされません (構文エラー) forall
。キーワードをサポートするには拡張機能が必要です。
基本的に、キーワードには 3 つの異なる一般的な使用法がありforall
(または、少なくともそう思われます)、それぞれに独自の Haskell 拡張があります: ScopedTypeVariables
, RankNTypes
/ Rank2Types
, ExistentialQuantification
.
上記のコードは、これらのいずれかが有効になっていても構文エラーを取得しませんが、有効になっている型チェックのみを取得しますScopedTypeVariables
。
スコープ型変数:
スコープ型変数は、where
句内のコードの型を指定するのに役立ちます。b
とval :: b
同じものをb
作りますfoob :: forall a b. (b -> b) -> b -> (a -> b) -> Maybe a -> b
。
紛らわしい点forall
:型から を省略しても、実際にはまだ暗黙的にそこにあると聞くかもしれません。(ノーマンの回答から:「通常、これらの言語は多態型から forall を省略します」)。この主張は正しいがforall
、 の使用ではなく、 の他の使用について言及してScopedTypeVariables
いる。
ランク N タイプ:
が有効な場合を除いて、mayb :: b -> (a -> b) -> Maybe a -> b
と同等のものから始めましょう。mayb :: forall a b. b -> (a -> b) -> Maybe a -> b
ScopedTypeVariables
これは、すべてのa
およびに対して機能することを意味しb
ます。
このようなことをしたいとしましょう。
ghci> let putInList x = [x]
ghci> liftTup putInList (5, "Blah")
([5], ["Blah"])
this の型は何liftTup
ですか? ですliftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
。その理由を確認するために、コード化してみましょう。
ghci> let liftTup liftFunc (a, b) = (liftFunc a, liftFunc b)
ghci> liftTup (\x -> [x]) (5, "Hello")
No instance for (Num [Char])
...
ghci> -- huh?
ghci> :t liftTup
liftTup :: (t -> t1) -> (t, t) -> (t1, t1)
「うーん..タプルには同じ型が2つ含まれている必要があるとGHCが推論するのはなぜですか?それらがそうである必要はないことを伝えましょう」
-- test.hs
liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)
ghci> :l test.hs
Couldnt match expected type 'x' against inferred type 'b'
...
うーん。ここで GHC は、 とが必要なため、申請liftFunc
を許可しません。私たちの関数は、あらゆる可能性を受け入れる関数を取得したいのです!v
v :: b
liftFunc
x
x
{-# LANGUAGE RankNTypes #-}
liftTup :: (forall x. x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)
したがってliftTup
、すべてx
の場合に機能するわけではなく、機能するのは取得する機能です。
実存的定量化:
例を使用しましょう:
-- test.hs
{-# LANGUAGE ExistentialQuantification #-}
data EQList = forall a. EQList [a]
eqListLen :: EQList -> Int
eqListLen (EQList x) = length x
ghci> :l test.hs
ghci> eqListLen $ EQList ["Hello", "World"]
2
N型との違いは?
ghci> :set -XRankNTypes
ghci> length (["Hello", "World"] :: forall a. [a])
Couldnt match expected type 'a' against inferred type '[Char]'
...
Rank-N-Types では、式がすべての可能なsforall a
に適合する必要があることを意味しました。a
例えば:
ghci> length ([] :: forall a. [a])
0
空のリストは、どのタイプのリストとしても機能します。
したがって、存在量化では、定義forall
内の s は、含まれる値がすべての適切な型である必要があるのではなく、任意の適切な型である可能性があることを意味します。data