予備的注記:ここに提示された証拠を考慮して、私はあなたが以下を使用していると仮定します:
type GenericQ r = forall a . Data a => a -> r
sybから、そして
gmapQ :: Data a => (forall d. Data d => d -> u) -> a -> [u]
からData.Data
。
間違えたら教えてください。また、forall
以下のsは明示的に記述されます。
ここには目に見える以上のものがあります。Li-yao Xiaが示唆しているように、それはのタイプを含む一般化の問題ですop
。あなたの最初の定義について3つの関連する事実がありますshallowest
:
一般化の前に、の推定タイプはop
ですData d => d -> f a
。Data d
制約がある場合、単相制限のルール1(レポートのサブセクション4.5.5を参照)はd
、このタイプでは一般化できないことを意味します。
の本文ではshallowest
、op
2か所に表示されます。最初のものはop z
でありz :: a1
、の署名によってトップレベルでバインドおよび制約されますshallowest
。結論として、この発生は引数タイプの一般化を必要とop
しないということです。それに関する限り、タイプはタイプ変数で単形であるop
可能性がforall f a. a1 -> f a
ありますa1
(この用語はレポートのサブセクション4.5.4から取得しました)。
ただし、他の発生はgmapQ op z
です。gmapQ
ランク2タイプであり、多形引数が必要です。そのため、op
Li-yao Xiaの回答の最後に記載されているように、この発生には引数タイプの一般化が必要です。
#1と#3は矛盾する要件であるため、型エラーが発生します。これは、単相制限を無効にするかop
、署名付きの引数型で多態性を要求することで回避できます。op
#2で説明した他の発生のおかげで、状況は2つの発生を含む不一致として報告されます。
以下は、何が起こっているかを確認するのに役立つ可能性のある、より最小限の拡張例です。(ほかに、あなたは、GHCiのに次のスニペットをウンチしようとしている場合は-XRankNTypes
、あなたも設定する必要があります-XMonomorphismRestriction
し、-XNoExtendedDefaultRules
同じ結果を見るために。)
これはランク2タイプの関数であり、次の役割を果たしgmapQ
ます。
glub :: (forall x. Show x => x -> String) -> String
glub f = f 7
それでは、以下を含むシナリオと同様のシナリオを試してみましょうshallowest
...
foo1 :: forall a. Show a => a -> String
foo1 x = bar x ++ glub bar
where
bar = show
...そしてあなたのエラーがあります:
<interactive>:506:23: error:
• Couldn't match type ‘x’ with ‘a’
‘x’ is a rigid type variable bound by
a type expected by the context:
forall x. Show x => x -> String
at <interactive>:506:18-25
‘a’ is a rigid type variable bound by
the type signature for:
foo1 :: forall a. Show a => a -> String
at <interactive>:505:1-38
Expected type: x -> String
Actual type: a -> String
• In the first argument of ‘glub’, namely ‘bar’
In the second argument of ‘(++)’, namely ‘glub bar’
In the expression: bar x ++ glub bar
• Relevant bindings include
bar :: a -> String (bound at <interactive>:508:3)
x :: a (bound at <interactive>:506:5)
foo1 :: a -> String (bound at <interactive>:506:1)
の署名がbar
必要な場所にワイルドカードを追加すると、少し示唆に富む追加のエラーが発生します。
foo2 :: forall a. Show a => a -> String
foo2 x = bar x ++ glub bar
where
bar :: _
bar = show
• Found type wildcard ‘_’ standing for ‘a -> String’
Where: ‘a’ is a rigid type variable bound by
the type signature for:
foo2 :: forall a. Show a => a -> String
at <interactive>:511:1-38
To use the inferred type, enable PartialTypeSignatures
• In the type signature: bar :: _
In an equation for ‘foo2’:
foo2 x
= bar x ++ glub bar
where
bar :: _
bar = show
• Relevant bindings include
x :: a (bound at <interactive>:512:5)
foo2 :: a -> String (bound at <interactive>:512:1)
ワイルドカード「の略」が、の型シグネチャによってバインドさa -> String
れるのとは別の事実としてどのように記述されているかに注意してください。これは、上記のポイント2で触れた、型変数の単型と多型の違いに対応していると思います。a
foo2
bar
ポリモーフィック型の署名を与えると、それが機能します。
foo3 :: forall a. Show a => a -> String
foo3 x = bar x ++ glub bar
where
bar :: forall b. Show b => b -> String
bar = show
また、バーの定義を意味のあるものにすることも同様です。これにより、バーを「単純なパターンバインディング」ではなく「関数バインディング」にすることで、単相性の制限を回避できます。
foo4 :: forall a. Show a => a -> String
foo4 x = bar x ++ glub bar
where
bar x = show x
完全を期すために、型に制約がないということは、単相性の制限がないことを意味することに注意してください。
foo5 :: forall a. Show a => a -> String
foo5 x = bar x ++ glub bar
where
bar = const "bar"
関連する状況では、bar
2回使用しますが、ランク2関数は使用しません。
foo6 x y = bar x ++ bar y
where
bar = show
GHCはどのタイプを推測しfoo6
ますか?
GHCi> :t foo6
foo6 :: Show a => a -> a -> [Char]
引数は同じ型を取得します。そうでない場合は、の一般化がbar
必要になり、型シグネチャ(またはポイントフルネスなど)が必要になります。
foo7 x y = bar x ++ bar y
where
bar :: forall a. Show a => a -> String
bar = show
GHCi> :t foo7
foo7 :: (Show a1, Show a2) => a1 -> a2 -> [Char]
私はまだそれについて言及しなかったので、ここにあなたの2番目のアナログがありますshallowest
:
foo8 :: forall a. Show a => a -> String
foo8 x = bar x
where
bar = show
ここではbar
実際には一般化されていないことを強調する価値があります。それは型変数では単形ですa
。:foo7
ではなくをいじることで、この例を破ることができますbar
。
foo9 = bar
where
bar :: _
bar = show
この場合、bar
は一般化されておらず、どちらも一般化されていませんfoo
(現在はポイントフリーで署名なし)。つまり、単相型変数は決して解決されません。モニック射制限のルール2に関しては、あいまいな型変数になります。
<interactive>:718:14: error:
• Found type wildcard ‘_’ standing for ‘a0 -> String’
Where: ‘a0’ is an ambiguous type variable
To use the inferred type, enable PartialTypeSignatures
• In the type signature: bar :: _
In an equation for ‘foo9’:
foo9
= bar
where
bar :: _
bar = show
• Relevant bindings include
foo9 :: a0 -> String (bound at <interactive>:716:5)
<interactive>:719:13: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘show’
prevents the constraint ‘(Show a0)’ from being solved.
Relevant bindings include
bar :: a0 -> String (bound at <interactive>:719:7)
foo9 :: a0 -> String (bound at <interactive>:716:5)
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show a => Show (ZipList a)
-- Defined in ‘Control.Applicative’
instance Show Constr -- Defined in ‘Data.Data’
instance Show ConstrRep -- Defined in ‘Data.Data’
...plus 64 others
...plus 250 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: show
In an equation for ‘bar’: bar = show
In an equation for ‘foo9’:
foo9
= bar
where
bar :: _
bar = show
bar
の定義に型シグネチャを追加してfoo9
も役に立ちません。エラーが報告されるポイントを変更するだけです。bar
制約のないものに変更するbar
と、との両方を一般化できるため、エラーがなくなりますfoo
。