AliasK
@AliasK

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

HaskellのIntegerに関するパターンマッチについて

Integerのパターンマッチング

(実際のコードの問題点を抽象したコードを用います)
以下の問題はどうして起こるのでしょうか?

発生している問題

Integerに対して数学的には正しい同値分類を、VSCodeのHaskellコンパイラがMECEだと認めてくれません。曰く漏れがあるそうです。
ghciで単体テストは通過しているので、最悪、警告を無視して開発を続けますが、多倍長整数特有の現象で、例えば、
"コンパイラから値の全容が見えない"
みたいなのものが存在するなら、この機会に詳しく知りたいです。
また、もしも実際に取りうる値を見逃している場合、その値が何か教えてください。
そうでない場合、パターンとして「その他(_ , otherwise)」を設けるべきか否か、助言いただけると幸いです。

こういう時ってどう対処すればいいんでしょうか…。

問題となっているコード
es :: Integer -> Char
es k = case signum k of{0 -> 'Z' ; 1 -> 'P'; -1 -> 'M'}

ess :: Integer -> Char
ess k
  | k < 1 && k > -1 = 'Z'
  | k >= 1 = 'P'
  | k <= -1 = 'M'

--比較用
ees:: Integer -> Char
ees k 
     | k > 0 = 'M'
     | k <= 0 = 'N'

--警告内容
{- compile(-Wincomplete-patterns)
Pattern match(es) are non-exhaustive
In a case alternative:
    Patterns of type ‘Integer’ not matched:
        --esに対しては
        p where p is not one of {-1, 0, 1}
        --ess, eesに対しては
        _
-}

essは、{==0,>0,<0}も試しましたが同様です。

0

1Answer

すみません自己解決しました!
エラーメッセージの英語の読解ミスで、In a case alternative :以下の部分が、具体的に漏れと判断された事例であると認識できていませんでした。
つまりコンパイラは、その部分でまさに
「おまえ、Integerには{0,1,-1}以外の値もあるけどそれについて書いてないよ」
と言ってくれていたわけですね…。試しに

>> :set -Wincomplete-patterns
>> es = \(k :: Integer)-> case signum k of {0 -> 0; 1 -> 1} :: Integer

をghciに通してみると、該当部分の末尾が...p where p is not one of {0, 1}と帰ってきたので気付くことができました。
Haskellには篩型がないので、事後条件がコンパイラにはわからないという事なのでしょう。
つまり
GHCは、signum :: Integer -> Integer の値域が "厳密に{0,1,-1}であること" を知らない
という事です。 組み込み関数だろお前ふざけんな! まあ型横断的な関数なので仕方ない... わけないよ。わからない原因それじゃないし!
とかいう愚痴はさておいて、こういう罠があることは知っておかなくちゃいけないですね。

というわけなので、「その他」を追加するという戦略を安心して取ろうと思います。

0Like

Your answer might help someone💌