068 の調査から派生。As-pattern x@(p, q) = (1, 2) を、
x = (1, 2) p = case x of (a, b) -> a
のように変換すると型エラーする。(p = case (1, 2) of ... なら OK)
これが、Rename された結果に近い、以下のような書き換えでもだめ
x = (1, 2) p = snd x
p の型が Num t => t のようになるべきところが、--ddump-assump の時点ですでにそうなっていないので、型推論以前の段階に問題があるように見えるが…。
Thih のコードに問題があるわけではないだろうし、まだ見当がついていない。
ひとまず 068 の仮対処で、つい、as-pattern でないものを、 as-pattern に変換するときの一時変数を "_" にしてさぼってしまったが、 本件対処するためには、ここに fresh な変数を用意しないといけない。
この件はちょっと長引きそうな気がしている。ひとつひとつ、確認していこう。
まず、本件に関する testcases をひとつディレクトリを掘ってまとめておく。 (testcases/073)
ptype1 と ptype2 に本質的な違いはない。ptype2 をつかったほうが、 生成される core がシンプルになって調査が楽かもしれないので、以降こちらを用いる。
ptype2.hs:
main = do print p where x = (1, 2) p = fst x
これをコンパイルすると、bunnyc: Error: dictionary not found: ("Prelude.Show",Tyvar "v2321" Star,[]) となる。
以下が、その core0 だが、Main.l1.l0.p の型が Num t => t ではなく t になっているのが、 辞書渡しが解決できない理由にも見える。 (一方で、p のなかで Defaulting してしまって、v2321 = Integer にしてしまうという手もありそうだが、それでは、別件(gcd など)に対応できないかも)
(Main.main :: (Prelude.IO ())) = let (Main.l1.l0.p :: v2321) = ((Prelude.fst :: (((Prelude.(,) t2) t3) -> t2)) (Main.l1.l0.x :: ([Prelude.Num v2314,Prelude.Num v2315] :=> ((Prelude.(,) v2314) v2315)))) (Main.l1.l0.x :: ([Prelude.Num v2314,Prelude.Num v2315] :=> ((Prelude.(,) v2314) v2315))) = (((Prelude.(,) :: (t9 -> (t10 -> ((Prelude.(,) t9) t10)))) ((Prelude.fromInteger :: ([Prelude.Num t11] :=> (Prelude.Integer -> t11))) (1 :: Prelude.Integer))) ((Prelude.fromInteger :: ([Prelude.Num t12] :=> (Prelude.Integer -> t12))) (2 :: Prelude.Integer))) in ((Prelude.print :: ([Prelude.Show t15] :=> (t15 -> (Prelude.IO ())))) (Main.l1.l0.p :: v2321))
Typing モジュールによる型推論がまちがっているとも考えづらいが(Thih そのままなので)、 自前でつくっている toBg に問題がある可能性は考えられる(sa. 088)
ptype2.hs を少し変形して、次のようにすると通る (ptype2m.hs)。
main = do print p where p = fst x where x = (1, 2)
この場合には、p の型は Num t => t と推論されており、それに基づいて 適切に辞書渡しが行われてる:
(Main.main :: (Prelude.IO ())) = let (Main.l1.l0.p :: ([Prelude.Num v2321] :=> v2321)) = \(Main.l1.l0.p.DARG0 :: Ä) -> let (Main.l1.l0.l0.l0.x :: ([Prelude.Num v2315,Prelude.Num v2316] :=> ((Prelude.(,) v2315) v2316))) = \(Main.l1.l0.l0.l0.x.DARG0 :: Ä) (Main.l1.l0.l0.l0.x.DARG1 :: Ä) -> (((Prelude.(,) :: (t6 -> (t7 -> ((Prelude.(,) t6) t7)))) (((Prelude.fromInteger :: ([Prelude.Num t8] :=> (Prelude.Integer -> t8))) (Main.l1.l0.l0.l0.x.DARG0 :: Å)) (1 :: Prelude.Integer))) (((Prelude.fromInteger :: ([Prelude.Num t9] :=> (Prelude.Integer -> t9))) (Main.l1.l0.l0.l0.x.DARG1 :: Å)) (2 :: Prelude.Integer))) in ((Prelude.fst :: (((Prelude.(,) t12) t13) -> t12)) (((Main.l1.l0.l0.l0.x :: ([Prelude.Num v2315,Prelude.Num v2316] :=> ((Prelude.(,) v2315) v2316))) (Main.l1.l0.p.DARG0 :: Å)) ${Prelude.Integer Prelude.Num})) in (((Prelude.print :: ([Prelude.Show t17] :=> (t17 -> (Prelude.IO ())))) ${Prelude.Integer Prelude.Show}) ((Main.l1.l0.p :: ([Prelude.Num v2321] :=> v2321)) ${Prelude.Integer Prelude.Num}))
なので、ひとつは、型変換まえの Rename でこのように式変形してしまうかとも 考えたのだが、p の binding が複雑だった場合(pattern binding など)にこのように 変形するのは複雑になってしまうのと、以下のケースにやはりエラーするので、 苦労して変形したところで、解決になっていない。
ptype2n.hs:
main = let x = (1, 2) in let p = fst x in print p
なので、型推論以前(toBg 含め)の問題かとは思われるが、 仮対処として type-checking (DictPass) にて p の型に述語 (Num t) を補うことを考えてみたい。
DictPass にて Pred を補うようにしたことで、ptype1, 2 ともに期待通り変換されるようになった。以下は、ptype2.hs のコア。Main.l1.l0.p の型に Num b9 という Pred が補われ、 辞書渡しが行われている:
(Main.main :: (Prelude.IO ())) = let (Main.l1.l0.x :: ([Prelude.Num v2240,Prelude.Num v2241] :=> ((Prelude.(,) v2240) v2241))) = \(Main.l1.l0.x.DARG0 :: Ä) (Main.l1.l0.x.DARG1 :: Ä) -> (((Prelude.(,) :: (t4 -> (t5 -> ((Prelude.(,) t4) t5)))) (((Prelude.fromInteger :: ([Prelude.Num t6] :=> (Prelude.Integer -> t6))) (Main.l1.l0.x.DARG0 :: Å)) (1 :: Prelude.Integer))) (((Prelude.fromInteger :: ([Prelude.Num t7] :=> (Prelude.Integer -> t7))) (Main.l1.l0.x.DARG1 :: Å)) (2 :: Prelude.Integer))) in let (Main.l1.l0.p :: ([Prelude.Num b9] :=> b9)) = \(Main.l1.l0.p.DARG0 :: Ä) -> ((Prelude.fst :: (((Prelude.(,) t11) t12) -> t11)) (((Main.l1.l0.x :: ([Prelude.Num v2240,Prelude.Num v2241] :=> ((Prelude.(,) v2240) v2241))) (Main.l1.l0.p.DARG0 :: Å)) ${Prelude.Integer Prelude.Num})) in (((Prelude.print :: ([Prelude.Show t15] :=> (t15 -> (Prelude.IO ())))) ${Prelude.Integer Prelude.Show}) ((Main.l1.l0.p :: ([Prelude.Num b9] :=> b9)) ${Prelude.Integer Prelude.Num}))
今回の修正により、エラーするようになってしまった sample プログラムもある。 testcases に降格する。これらは、それぞれ新規 issue をたてる。
また、本件対処によって test/samples に加えられたもの: