# 083: litpattern.hs で renPat: LitExp (LitInteger 0 (1,3)) [↑up](bunny_notes) - issued: 2020-05-18 - 分類: A サンプルコードが fail - status: Closed (2020-05-20) ## 概要 lib/Prelude.hs に gcd を定義しようとして発覚。 パターンに整数リテラルを書くとエラー。 litpattern.hs $$
{
f 0 = "zero"
f _ = "non-zero"
main = do putStrLn $ f 1
          putStrLn $ f 0
$$}

類似: litpattern2.hs, litpattern3.hs

なお、似ているが case 式の場合には異る箇所でエラーしたため、
別 issue ([084](bissue084)) とした。

## 概要
## 2020-05-18

最初、リテラルを疑似コンストラクタで表現するのかなとも思ったが、
Bounded とはいえ値の個数がおおく(それはなんとかしたとしても)、
数値リテラルは多相なので、うまくいきそうにない。

そのことを考慮すると、
== 演算子をもちいるような形に desuger してやるしかないのではないか。

参考として、GHC がどうしているのかを、
${ghc -ddump-ds-preopt testcases/litpattern.hs} で確認:

$$
{
f :: forall a. (Eq a, Num a) => a -> [Char]
[LclId]
f = \ (@ a_a211)
      ($dEq_a2hL :: Eq a_a211)
      ($dNum_a2hM :: Num a_a211) ->
      let {
        $dNum_a2ds :: Num a_a211
        [LclId]
        $dNum_a2ds = $dNum_a2hM } in
      let {
        $dEq_a212 :: Eq a_a211
        [LclId]
        $dEq_a212 = $dEq_a2hL } in
      letrec {
        f_a2du :: a_a211 -> [Char]
        [LclId]
        f_a2du
          = \ (ds_d2kK :: a_a211) ->
              let {
                fail_d2l2 :: GHC.Prim.Void# -> [Char]
                [LclId]
                fail_d2l2
                  = \ (ds_d2l3 [OS=OneShot] :: GHC.Prim.Void#) ->
                      GHC.CString.unpackCString# "non-zero"# } in
              case ==
                     @ a_a211 $dEq_a212 ds_d2kK (fromInteger @ a_a211 $dNum_a2ds 0)
              of wild_00 {
                False -> fail_d2l2 GHC.Prim.void#;
                True -> GHC.CString.unpackCString# "zero"#
              }; } in
      f_a2du

$$}

単純化すると、次のように書き換えているようだ (litpattern-ds.hs):

$$
{
f = \x ->
  let
    fail' = "non-zero"
  in
    case (==) x 0 of
      False -> fail'
      True  -> "zero"
$$}

fail の内容が変数に束縛されていて、複数の個所から呼べるように(上の例では一か所だが)なっているのが、変換のヒントのように見える。

どういうアルゴリズムでこのように変換するかは、考えどころ。

なんとなくだが、以下のように変換してから [064](bissue064)
の問題と統一的に扱うのが良い気がする。

$$
{
f x | x == 0 = "zero"
f _          = "non-zero"
$$}

## 2020-05-19

まず、↑のように ${f x | x == 0 = "zero"} のような形の式をただしく扱えるようにする。
現状では、Rename の時点で FAIL を ${error "Error: Non-exhaustive patterns."}
におとしてしまっていたので、これを、Prim.FAIL とする。

さらに、TrCore にて、transExpr (Fatbar e f) とあった場合に、e, f それぞれを
Core に直したうえで、e にあった FAIL を f を変換したものに置き換えるようにした。

これで、この形の式は通るようになった。

つぎは、${f 0 = ...} を ${f x | x == 0 = ...} に変換すればいいはず。

## 2020-05-20

renDecl にて、いままでどおりのリネームを行うまえに、左辺のパターンに
リテラルがあった場合には、上述のような変換をするようにした。これにより、
想定していたケースには対応、本件はクローズとする。

A.Exp のすべてに対応しないといけないわけではないはずだが、仕様を確認して、
必要十分な対処になっているかどうかは確認したい。これは、別 issue ([086](bissue086)) 
とする。

また、litpattern2.hs では、浮動小数点リテラルに未対応なのでコケてしまった。
これも、別問題なので新規 issue ([087](bissue087)) とする。

lib/Prelude.hs において、本件のためにコメントアウトしてあった、gcd, lcm, (^) の定義は復活。

- litpattern.hs: sample217.hs
- litpattern3.hs: sample218.hs
- gcdlcm.hs: sample219.hs