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) とした。
最初、リテラルを疑似コンストラクタで表現するのかなとも思ったが、 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 の問題と統一的に扱うのが良い気がする。
f x | x == 0 = "zero" f _ = "non-zero"
まず、↑のように 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 = ... に変換すればいいはず。
renDecl にて、いままでどおりのリネームを行うまえに、左辺のパターンに リテラルがあった場合には、上述のような変換をするようにした。これにより、 想定していたケースには対応、本件はクローズとする。
A.Exp のすべてに対応しないといけないわけではないはずだが、仕様を確認して、 必要十分な対処になっているかどうかは確認したい。これは、別 issue (086) とする。
また、litpattern2.hs では、浮動小数点リテラルに未対応なのでコケてしまった。 これも、別問題なので新規 issue (087) とする。
lib/Prelude.hs において、本件のためにコメントアウトしてあった、gcd, lcm, (^) の定義は復活。