# 092: gcdlcm.hs が通らなくなった [↑up](bunny_notes) - issued: 2020-05-23 - 分類: A サンプルコードが fail - status: Closed (2020-05-27) # 概要 [073](bissue073) の対処により、これまで通っていたテストが通らなくなってしまったもののひとつ。 lib/Prelude.hs の lcm がエラーするようになったので、これをコメントアウトしたため、 lcm を呼び出していたプログラムは当然ながらコンパイルできなくなった。 gcdlcm.hs は、[083](bissue083) で sample219.hs として追加されたもの。 ## 調査ログ ## 2020-05-27 pss の保持と、lookupDictArg の処理があっておらず、ネストされた Let 式において、 辞書の受け渡しに失敗していた。 tcbind では、↓★部で辞書引数をうけとる関数の名前 n を保持している。 そして、その二行したで、一つ外側の pss' と連結。(これがよくない) $$
{
tcBind :: Bind -> ClassEnv -> Maybe TcState -> (Bind, TcState)
tcBind (Rec bs) ce maybest = tbloop st0 bs []
  where
    tbloop :: TcState -> [(Var, Expr)] -> [(Var, Expr)] -> (Bind, TcState)
    tbloop st []     res = (Rec (reverse res), st) 
    tbloop st (b:bs) res = let (ve, st') = tcbind b st
                           in tbloop st' bs (ve:res)

    st0 = case maybest of
            Just st' -> st'
            Nothing  -> mkTcState ce [] nullSubst 0

    tcbind :: (Var, Expr) -> TcState -> ((Var, Expr), TcState)
    tcbind (v@(TermVar n qt@(qs :=> t)), e) st
      | isOVExpr e = ((v, e), st)
      | otherwise =
        let pss = (zip qs (repeat n)) -- ★
            pss' = tcPss st
            st' = st{tcPss=(pss++pss')}
            (e', st'') = runState (tcExpr e qt) st'
            num = tcNum st''
        in
          if null qs then ((v, e'), st{tcNum=num})
          else ((v, Lam (mkVs n qs) e'), st{tcNum=num})
    tcbind _ _ = error "tcbind: must not occur."
$$}

lookupDictArg では、連結された pss+pss' 全体に通し番号を振っている(↓※部)ので、
各関数における正しい引数番号を再現できていなかった。

$$
{
lookupDictArg :: (Id, Tyvar) -> TC (Maybe Var)
lookupDictArg (c, y) = do
  s <- getSubst
  pss <- getPss
  ce <- getCe
  let d = zip (map (\((IsIn i t), _) -> (i, apply s t)) pss) [(0::Int)..] -- ※
      lookupDict (k, tv) (((c, tv'), i):d')
        | tv == tv' && c `isin` k = Just i
        | otherwise = lookupDict (k, tv) d'
      lookupDict _ [] = Nothing
      c1 `isin` c2 = (c1 == c2)|| (or $ map (`isin` c2) (super ce c1))
      ret = case lookupDict (c, TVar y) d of
        Nothing -> Nothing
        Just j  -> let (_, n) = pss !! j
                   in Just $ TermVar (n ++ ".DARG" ++ show j) ([] :=> TGen 100)
  return ret
$$}

### 修正内容

pss を格納するときに、番号も含めて生成してしまうことにした:

$$
{
+++ b/compiler/src/DictPass.hs
@@ -46,7 +46,8 @@ tcBind (Rec bs) ce maybest = tbloop st0 bs []
     tcbind (v@(TermVar n qt@(qs :=> t)), e) st
       | isOVExpr e = ((v, e), st)
       | otherwise =
-        let pss = (zip qs (repeat n))
+        let ds = zipWith (++) (repeat (n ++ ".DARG")) (map show [0..])
+            pss = (zip qs ds)
             pss' = tcPss st
             st' = st{tcPss=(pss++pss')}
             (e', st'') = runState (tcExpr e qt) st'
$$}

lookupDictArg 側では、単純にそれを用いる:

$$
{
@@ -203,16 +204,15 @@ lookupDictArg (c, y) = do
   s <- getSubst
   pss <- getPss
   ce <- getCe
-  let d = zip (map (\((IsIn i t), _) -> (i, apply s t)) pss) [(0::Int)..]
-      lookupDict (k, tv) (((c, tv'), i):d')
-        | tv == tv' && c `isin` k = Just i
+  let d = map (\((IsIn i t), n) -> ((i, apply s t), n)) pss
+      lookupDict (k, tv) (((c, tv'), s):d')
+        | tv == tv' && c `isin` k = Just s
         | otherwise = lookupDict (k, tv) d'
       lookupDict _ [] = Nothing
       c1 `isin` c2 = (c1 == c2)|| (or $ map (`isin` c2) (super ce c1))
       ret = case lookupDict (c, TVar y) d of
         Nothing -> Nothing
-        Just j  -> let (_, n) = pss !! j
-                   in Just $ TermVar (n ++ ".DARG" ++ show j) ([] :=> TGen 100)
+        Just s  -> Just $ TermVar s ([] :=> TGen 100)
   return ret
$$}

これで、lib/Prelude.hs における lcm 定義はエラーしなくなり、
gcdlcm.hs, gcd2lcm2.hs ともに通るようになった。

- gcdlcm.hs -> sample227.hs