{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ExistentialQuantification #-}
import Data.Proxy
data Foo = FooA | FooB
class Bar (a :: k) where
bar :: Proxy a -> Int
instance Bar FooA where
bar _ = 1
instance Bar FooB where
bar _ = 2
foo1 :: forall (a :: Foo). Proxy a -> (Bar a => Proxy a)
foo1 p = p
data BarProxy = BarProxy (forall a. Bar a => Proxy a)
foo2 :: forall (a :: Foo). Proxy a -> BarProxy
foo2 p = BarProxy (foo1 p)
main = print "Hello World"
このコードでは:
foo1
、任意のProxy a
場所a
種類のものであるがFoo
、返すProxy a
ようa
にインスタンスを持っているのBar
?BarProxy
コンストラクタ任意の受け入れProxy a
、どこa
のインスタンスを持っているのBar
?それはどう違うのdata BarProxy = forall a. BarProxy (Bar a => Proxy a)
ですか?foo2 p = BarProxy (foo1 p)
以下のエラーで失敗するのはなぜですか?Test6.hs:27:20: error:
• Couldn't match type ‘a1’ with ‘a’
‘a1’ is a rigid type variable bound by
a type expected by the context:
forall (a1 :: Foo). Bar a1 => Proxy a1
at Test6.hs:27:10-26
‘a’ is a rigid type variable bound by
the type signature for:
foo2 :: forall (a :: Foo). Proxy a -> BarProxy
at Test6.hs:26:1-46
Expected type: Proxy a1
Actual type: Proxy a
• In the first argument of ‘BarProxy’, namely ‘(foo1 p)’
In the expression: BarProxy (foo1 p)
In an equation for ‘foo2’: foo2 p = BarProxy (foo1 p)
• Relevant bindings include
p :: Proxy a (bound at Test6.hs:27:6)
foo2 :: Proxy a -> BarProxy (bound at Test6.hs:27:1)
|
27 | foo2 p = BarProxy (foo1 p)
| ^^^^^^
いいえ。私の理解では、の署名はfoo1
と同じですforall (a :: Foo). Bar a => Proxy a -> Proxy a
(ドキュメントは見つかりませんでしたが)。ghciでは、:t foo1
を与えfoo1 :: Bar a => Proxy a -> Proxy a
ます。任意のProxy a
場所a
種類のものであるFoo
とのインスタンスをBar
、それが返されますProxy a
。
いいえ。コンストラクターにBarProxy
はランク2のポリモーフィック型があり(forall a. Bar a => Proxy a) -> BarProxy
ます。引数はこの手段p
に渡すことができるBarProxy
場合にのみ、p
タイプがあるProxy a
ため、すべてのタイプa
のインスタンスですBar
。存在記号が必要な場合は、次のように記述できます。
data BarProxy = forall a. Bar a => BarProxy (Proxy a)
または
data BarProxy where
BarProxy :: forall a. Bar a => Proxy a -> BarProxy
-XGADTs
有効。
実存型とユニバーサルBarProxy
型を呼びましょう。存在記号の場合、引数の型はまたは(存在記号で)のいずれかである必要があります。一方、全称記号の場合は、と(同じセットで全称記号)の両方を入力する必要があります。以下の3つのプロキシについて考えてみましょう。forall a. Bar a => Proxy a -> BarProxy
BarProxy
(forall a. Bar a => Proxy a) -> BarProxy
BarProxy
p
Proxy FooA
Proxy FooB
{a | a is an instance of Bar} = {FooA,FooB}
p
Proxy FooA
Proxy FooB
proxyFooA :: Proxy FooA
proxyFooA = Proxy
proxyFooB :: Proxy FooB
proxyFooB = Proxy
proxyPoly :: forall a. Proxy a
proxyPoly = Proxy
ExistentialBarProxy
は3つのうちのいずれかを受け入れますが、Universal1はのみを受け入れますproxyPoly
。
foo2 p = BarProxy (foo1 p)
実存のためにコンパイルしBarProxy
ます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加