# 068: pairbind.hs で qname not found [↑up](bunny_notes) - issued: 2020-05-09 - 分類: A サンプルコードが fail - status: Closed (2020-05-14) ## 概要 divMod のデフォルト実装がエラーしたことで発覚。 $$
{
  where (p, q) = (1, 2)
$$}

のような束縛がうまくいかない。

$$
{
  where (,) p q = (1, 2)
$$}

でもだめ。それぞれにテストケースを用意した (pairbind2, pairbind)

## 調査ログ
### 2020-05-09

左辺がコンストラクタのパターンの場合(これに関する記述は、
Haskell 2010 Language Report のどこにあるんだろ
${thih の 11.6.3 にはこの変換に関する記載あり})には、
複数の binding に変換してやればいいように思われる:

$$
{
C a b c ... = rhs

⇒

a = let e = rhs
      in case e of
        C x y z ... -> x

b = let e = rhs
      in case e of
        C x y z ... -> y

c = let e = rhs
      in case e of
        C x y z ... -> z
$$}

(この方針で patbind.hs を手で変換したのが patbind2.hs)

現状の実装では、renDecl や、そこから呼ばれている renFExp が、
関数名が isConName である場合を考慮していない。

およそ、以下のようなことをやっていくべき。

- 現状の renDecl, renFExp の動作を整理する
- InfixExp は fixity resolution をすませた上で、FunAppExp に変換して、統一的に処理するようにしたい
- その後、本件のケース(関数名が isConName だった場合)に対処する

また、関連 issue を2つたてた: ([069](bissue069), [070](bissue070))

### 2020-05-10

この変換は as-pattern にいったん直してから、as-pattern として扱った方がいいような気がしてきた。

つまり、${C a b c ...= rhs} は、いったん ${e@(C a b c ...) = rhs}
に変換してから、以下の変換を施す:

$$
{
e@(C a b c ...) = rhs

⇒
e = rhs

a = case e of
        C x y z ... -> x

b = case e of
        C x y z ... -> y

c = case e of
        C x y z ... -> z
$$}

### 2020-05-11

まずは As-pattern に対処してから、上述のように、パターンを as-pattern に変換する処理を追加したい。なので、まずは、明にかかれた As-pattern のケースを2つ追加した。

- pairbind3.hs
- pairbind4.hs

3, 4 の順に対処していけると思う。 

scanValueDecl2 で、AsPat に対する限定的な対処をいれて、pairbind3, pairbind4 
のケースに対しては As pattern から上述のような変換をするようにした。

ところが、その後でエラー。もともとは、TupleExp も FunAppExp に変換して統一的に扱うつもりだったが、調査のため、現状はわけて処理している。

pairbind3.hs の方は、${findCMs failed: "Prelude.(,)"},
pairbind4.hs の方は、${dictionary not found: ("Prelude.Show",Tyvar "v1865" Star,[])} となる。

pairbind4.hs と同様の変換をあらかじめ手でかいておいた、pairbind4b.hs
でも同じく ${dictionary not found: ("Prelude.Show",Tyvar "v1865" Star,[])}
となるため、今回追加した変換に問題があるのではなく、辞書渡し変換の潜在的な障害だと思われる。

なお、pairbind4b.hs で、x に型注釈をつける (pairbind4b.hs) と通る。

### 2020-05-14

pairbind4.hs に関して、この現象が再現する最小コードがどうなるか考えてみた。
以下の形にまで変形しても、エラーは再現した:

$$
{
main = do print p
            where
              x = (1, 2)
              p = case x of
                (a, b) -> a
$$}

つまり、Rename に追加した変換に問題があるのではなく、期待通り変換しても型変換に失敗しているということ。

なお、case 式に x ではなく、(1, 2) を直接与えるようにしたら通る:

$$
{
main = do print p
            where
              p = case (1, 2) of
                (a, b) -> a
$$}

それぞれの core0 を示す。まず、うまくいかない方(case に x を与えた方):

$$
{
---- ddumpCore ----
(Main.main :: (Prelude.IO ())) =
    let
        (Main.l1.l0.p :: v1873) =
            let
                (Main.l1.l0.l1.l0.F :: (((Prelude.(,) t6) t7) -> t6)) =
                    \(_Main.l1.l0.l1.l0.F.U1 :: ((Prelude.(,) t0) t1)) ->
                        case (_Main.l1.l0.l1.l0.F.U1 :: ((Prelude.(,) t0) t1)) (_Main.l1.l0.l1.l0.F.U1b :: ((Prelude.(,) t0) t1)) of
                            Prelude.(,) (_Main.l1.l0.l1.l0.F.U2 :: t2) (_Main.l1.l0.l1.l0.F.U3 :: t3) :: (t2 -> (t3 -> ((Prelude.(,) t2) t3))) -> 
                                (_Main.l1.l0.l1.l0.F.U2 :: t2)
                            
                
                
            in
              ((Main.l1.l0.l1.l0.F :: (((Prelude.(,) t8) t9) -> t8)) 
                (Main.l1.l0.x :: ([Prelude.Num v1860,Prelude.Num v1861] :=> ((Prelude.(,) v1860) v1861))))
        
        (Main.l1.l0.x :: ([Prelude.Num v1860,Prelude.Num v1861] :=> ((Prelude.(,) v1860) v1861))) =
            (((Prelude.(,) :: (t14 -> (t15 -> ((Prelude.(,) t14) t15)))) 
                ((Prelude.fromInteger :: ([Prelude.Num t16] :=> (Prelude.Integer -> t16))) 
                  (1 :: Prelude.Integer))) 
              ((Prelude.fromInteger :: ([Prelude.Num t17] :=> (Prelude.Integer -> t17))) 
                (2 :: Prelude.Integer)))
        
        
    in
      ((Prelude.print :: ([Prelude.Show t20] :=> (t20 -> (Prelude.IO ())))) 
        (Main.l1.l0.p :: v1873))
$$}

つぎに、うまくいった方(case に (1, 2) を直接書いた方):

$$
{
---- ddumpCore ----
(Main.main :: (Prelude.IO ())) =
    let
        (Main.l1.l0.p :: ([Prelude.Num v1866] :=> v1866)) =
            let
                (Main.l1.l0.l0.l0.F :: (((Prelude.(,) t7) t8) -> t7)) =
                    \(_Main.l1.l0.l0.l0.F.U1 :: ((Prelude.(,) t1) t2)) ->
                        case (_Main.l1.l0.l0.l0.F.U1 :: ((Prelude.(,) t1) t2)) (_Main.l1.l0.l0.l0.F.U1b :: ((Prelude.(,) t1) t2)) of
                            Prelude.(,) (_Main.l1.l0.l0.l0.F.U2 :: t3) (_Main.l1.l0.l0.l0.F.U3 :: t4) :: (t3 -> (t4 -> ((Prelude.(,) t3) t4))) -> 
                                (_Main.l1.l0.l0.l0.F.U2 :: t3)
                            
                
                
            in
              ((Main.l1.l0.l0.l0.F :: (((Prelude.(,) t9) t10) -> t9)) 
                (((Prelude.(,) :: (t11 -> (t12 -> ((Prelude.(,) t11) t12)))) 
                    ((Prelude.fromInteger :: ([Prelude.Num t13] :=> (Prelude.Integer -> t13))) 
                      (1 :: Prelude.Integer))) 
                  ((Prelude.fromInteger :: ([Prelude.Num t14] :=> (Prelude.Integer -> t14))) 
                    (2 :: Prelude.Integer))))
        
        
    in
      ((Prelude.print :: ([Prelude.Show t16] :=> (t16 -> (Prelude.IO ())))) 
        (Main.l1.l0.p :: ([Prelude.Num v1866] :=> v1866)))
$$}

Main.l1.l0.p の型がちがうなぁ。
これは、Assump (Typing の出力)時点ですでに異なっているのだが、
Thih 自体が間違っているとは思えない(これまでそんなことは一度もなかった)。
そういえば、case 式を Typing に与えるとき、自前でなんかしてたかなぁ…。

そのあたりが怪しい?

### 問題回避

ひとまず、case 式に直接右辺の式をあたえる (${p = case (1, 2) of ...} にする)
ことで問題を回避し、as-pattern の実装はすすめることにしたい。
根本解決になっていないし、
右辺が複雑な場合(ガードがあったり、where  節があったり)には、対応できないのだが。

この問題は切り出して、[別 issue](bissue073) とする。

### 調査継続

pairbind3.hs でエラーする (findCMs failed) 原因は、Predefined における漏れだった。
以下のように primConsMem の宣言に pairCfun を追加することで解決:

$$
{
--- a/compiler/src/PreDefined.hs
+++ b/compiler/src/PreDefined.hs
@@ -199,7 +199,7 @@ overloadedCfun = "#overloaded#" :>:
   Forall [Star, Star] ([] :=> (TGen 0 `fn` tString `fn` TGen 1))
 
 primConsMems :: [Assump]
-primConsMems  = [ unitCfun, nilCfun, consCfun
+primConsMems  = [ unitCfun, nilCfun, consCfun, pairCfun
$$}

### 解決

上記の対処にくわえて、コンストラクタ適用式を As-pattern に変換する処理を加えることで、
本 issue で想定していた testcases はクリア。

- pairbind : sample199
- pairbind2: sample200
- pairbind3: sample201
- pairbind4: sample202
- lsbind: sample203
- patbind2: samle204

本件ワークアラウンドへの正式対処は、別 issue [073](bissue073), [074](bissue074)
で継続することとして、本件はクローズ。