# 076: showlist2.hs が再びエラー、dictionary not found [↑up](bunny_notes) - issued: 2020-05-15 - 分類: A サンプルコードが fail - status: Closed (2020-10-01) ## 概要 [035](bissue035) 対処により、以前通っていた showlist2.hs がエラーするようになって しまったので、sample194 から再度降格。 現象: $$
{
$ ./trun testcases/showlist2.hs 
# 1. tcompile
source file: testcases/showlist2.hs
dst dir: /showlist2
doCompile ... done.
implicitPrelude ... done.
doCompile ... bunnyc: Error: dictionary not found: ("Prelude.Show",Tyvar "t40" Star,[(IsIn "Prelude.Show" (TVar (Tyvar "t44" Star)),"Main.l1.l0.l0.l0.showlist'.DARG0"),(IsIn "Prelude.Show" (TVar (Tyvar "t47" Star)),"Main.l1.l0.showList.DARG0")])
CallStack (from HasCallStack):
  error, called at src/DictPass.hs:261:25 in main:DictPass
$$}

## 調査ログ
## 2020-09-30
### 現象の絞り込み

問題を特定するために、showlist2.hs を小さくしていく。

以下のようにすると、エラーせずに実行できてしまった:

$$
{
main = do
  putStrLn $ showlist' [1]
    where
      showlist' []  = "[]" 
      showlist' [x] =  "[" ++ show x ++ "]"
$$}

以下では再現:

$$
{
main = do
  putStrLn $ showlist' [1]
    where
      showlist' [x] =  "[" ++ show x ++ "]"
      showlist' (x:xs) = "[" ++ foldl (\s t -> s ++ "," ++ show t) (show x) xs ++ "]"
$$}

もうすこし簡単にしてみた(showlist2b.hs):

$$
{
showlist' [x]    = show x
showlist' (x:xs) = showlist' xs
main = putStrLn $ showlist' [1]
$$}

これをコンパイルすると、次のようになる。

$$
{
$ ./trun testcases/showlist2b.hs
# 1. tcompile
source file: testcases/showlist2b.hs
dst dir: /showlist2b
doCompile ... done.
implicitPrelude ... done.
doCompile ... bunnyc: Error: dictionary not found: ("Prelude.Show",Tyvar "t20" Star,[(IsIn "Prelude.Show" (TVar (Tyvar "t22" Star)),"Main.showlist'.DARG0")])
CallStack (from HasCallStack):
  error, called at src/DictPass.hs:261:25 in main:DictPass
$$}

${--ddump-core0} の結果は次のとおり (showlist' 部のみ):

$$
{
(Main.showlist' :: ([Prelude.Show t22] :=> ([t22] -> [Prelude.Char]))) =
    \(_Main.showlist'.U1 :: ([Prelude.Show t7] :=> [t7])) ->
        case (_Main.showlist'.U1 :: ([Prelude.Show t7] :=> [t7])) (_Main.showlist'.U1b :: ([Prelude.Show t7] :=> [t7])) of
            Prelude.: (_Main.showlist'.U2 :: t10) (_Main.showlist'.U3 :: [t10]) :: (t10 -> ([t10] -> [t10])) -> 
                case (_Main.showlist'.U3 :: [t10]) (_Main.showlist'.U3b :: [t10]) of
                    Prelude.: (_Main.showlist'.U3 :: t18) (_Main.showlist'.U4 :: [t18]) :: (t18 -> ([t18] -> [t18])) -> 
                        ((Main.showlist' :: ([Prelude.Show t20] :=> ([t20] -> [Prelude.Char]))) 
                          (_Main.showlist'.U3 :: t18))
                    Prelude.[]  :: [t12] -> 
                        ((Prelude.show :: ([Prelude.Show t16] :=> (t16 -> [Prelude.Char]))) 
                          (_Main.showlist'.U2 :: t10))
                    
            Prelude.[]  :: [t8] -> 
                (Prim.FAIL :: t9)
$$}

${showlist' xs} に相当する部分が 
${((Main.showlist' :: ([Prelude.Show t20] :=> ([t20] -> [Prelude.Char]))) (_Main.showlist'.U3 :: t18))} なのだが、型引数が ${[t20]} なのに対して、
引数の型が ${t18} となっている(前者が型変数のリストだが、後者はリストでない)。

いっぽう、これによくにたプログラム(showlist2c.hs) ではエラーは発生しない。この core0 は以下のとおり:

$$
{
(Main.showlist' :: ([Prelude.Show t17] :=> ([t17] -> [Prelude.Char]))) =
    \(_Main.showlist'.U1 :: ([Prelude.Show t7] :=> [t7])) ->
        case (_Main.showlist'.U1 :: ([Prelude.Show t7] :=> [t7])) (_Main.showlist'.U1b :: ([Prelude.Show t7] :=> [t7])) of
            Prelude.: (_Main.showlist'.U2 :: t10) (_Main.showlist'.U3 :: [t10]) :: (t10 -> ([t10] -> [t10])) -> 
                (((Prelude.++ :: ([t12] -> ([t12] -> [t12]))) 
                    ((Prelude.show :: ([Prelude.Show t13] :=> (t13 -> [Prelude.Char]))) 
                      (_Main.showlist'.U2 :: t10))) 
                  ((Main.showlist' :: ([Prelude.Show t15] :=> ([t15] -> [Prelude.Char]))) 
                    (_Main.showlist'.U3 :: [t10])))
            Prelude.[]  :: [t8] ->  ""
$$}

同じ部分に着目すると、
${((Main.showlist' :: ([Prelude.Show t15] :=> ([t15] -> [Prelude.Char]))) (_Main.showlist'.U3 :: [t10])))}
のようになっていて、${[t15]} と ${[t10]} が対応している。

このあたりに着目してみるとよさそう。

### 原因調査

よくみてみると、型付けうんぬんのまえに、局所変数の解決がおかしい。

${(x:xs) -> showlist' xs} が、${: U3 U4 -> showlist' U3} になっている。
どこで狂った?

ああ、ちがうな。showlist2b.hs は次のような「平坦なcase式」に展開されるはずなのだが、

$$
{
showlist' xs = case xs of
  (y:ys) -> case ys of
    (z:zs) -> showlist' ys
    []     -> show y

main = do putStrLn $ showlist' [1]
          putStrLn $ showlist' [1, 2, 3]
$$}

上記における ys と、z がいずれも U3 になってしまっている。

パターンマッチングコンパイラ(Pattern.ns) が入れ子になっているときのα変換でしくっている(重複しておなじ文字番号をわりあててしまっている)ようだ。

## 2020-10-01

Pattern.hs において、Case 式が深くなるときに prefix にレベル相当を足してやればよかった。
簡単に以下のように修正:

$$
{
--- a/compiler/src/Pattern.hs
+++ b/compiler/src/Pattern.hs
@@ -93,7 +93,7 @@ reduceMatch ci n0 k0 vs0 qs0 def0 =
  
         matchClause c k (_:us) qs def =
           Clause c us' (match
-                        n
+                        (n ++ "._c")
                         (k + k)
                         (us' ++ us)
                         [(ps' ++ ps, e) | (PCon _ ps':ps, e) <- qs]
$$}

showlist2.hs は sample282.hs としてクローズ。