69971


[Swiftの付属型enumからデータを取り出すようなコードをHaskellで書きたい](https://ja.stackoverflow.com/questions/69968/swift%e3%81%ae%e4%bb%98%e5%b1%9e%e5%9e%8benum%e3%81%8b%e3%82%89%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e5%8f%96%e3%82%8a%e5%87%ba%e3%81%99%e3%82%88%e3%81%86%e3%81%aa%e3%82%b3%e3%83%bc%e3%83%89%e3%82%92haskell%e3%81%a7%e6%9b%b8%e3%81%8d%e3%81%9f%e3%81%84)で付属型enumと同じようにHaskellを書くにはどうすればいいかと聞きました。

確かに Swiftコード

[code]

    import Foundation
    enum Barcode {
        case upca(Int, Int, Int, Int)
        case qrcode(String)
    }
    func getBarcodeString(barcode: Barcode) -> String {
        switch barcode {
        case .upca(let a, let b, let c, let d):
            return String(a) + String(b) + String(c) + String(d)
        case .qrcode(let s):
            return s
        }
    }
    let barcode1 = Barcode.upca(1, 2, 3, 4)
    let barcode2 = Barcode.qrcode("A")
    print(getBarcodeString(barcode: barcode1))
    print(getBarcodeString(barcode: barcode2))
    
[/code]

は

[code]

    data Barcode = Upca Int Int Int Int
                 | Qrcode String
                 
    barcode1 = Upca 1 2 3 4
    barcode2 = Qrcode "A"
    
    getBarcodeString :: Barcode -> String
    getBarcodeString x = case x of
        Upca a b c d -> show a ++ show b ++ show c ++ show d
        Qrcode s     -> s
    
    main = do
        putStrLn $ getBarcodeString barcode1
        putStrLn $ getBarcodeString barcode2
    
[/code]

と同じと思ったのですが、上記コードから case内の`Qrcode s -> s` の部分を抜いて下記のようにしてみました。

[code]

    data Barcode = Upca Int Int Int Int
                 | Qrcode String
                 
    barcode1 = Upca 1 2 3 4
    barcode2 = Qrcode "A"
    
    getBarcodeString :: Barcode -> String
    getBarcodeString x = case x of
        Upca a b c d -> show a ++ show b ++ show c ++ show d
    
    main = do
        putStrLn $ getBarcodeString barcode1
        putStrLn $ getBarcodeString barcode2
    
[/code]

これをコンパイルして実行

まずコンパイル:

[code]

    % docker run -it --rm --name bar-haskell -v "$PWD":/tmp -w /tmp haskell:8 ghc -o Bar Bar.hs
    
[/code]

そして実行:

[code]

    % docker run -it --rm --name bar-haskell -v "$PWD":/tmp -w /tmp haskell:8 ./Bar
    1234
    Bar: Bar.hs:(8,22)-(9,56): Non-exhaustive patterns in case
    
[/code]

`1234`が表示されたあとで、 `Non-exhaustive patterns in case` が出ています。  
Swiftであれば switch
にすべてのパターンを網羅しないとコンパイルエラーになるので、実装漏れを防げるのですが、Haskellで同様に実装漏れに気づく方法はありますか？


CC BY-SA 4.0
2020-08-29T11:55:15.007
69970
2020-08-29T12:44:07.167
2020-08-29T12:38:34.203
9008
9008
question
swift haskell
実行時に Non-exhaustive patterns in case エラー になるので、実装漏れに気づけない


GHC のオプションに [`-Wincomplete-
patterns`](https://downloads.haskell.org/%7Eghc/latest/docs/html/users_guide/using-
warnings.html#ghc-flag--Wincomplete-patterns) があるのでこれを使ってみてください．

[code]

    $ ghc -Wincomplete-patterns  a.hs
    [1 of 1] Compiling Main             ( a.hs, a.o )
    
    a.hs:7:22: warning: [-Wincomplete-patterns]
        Pattern match(es) are non-exhaustive
        In a case alternative: Patterns not matched: (Qrcode _)
      |
    7 | getBarcodeString x = case x of
      |                      ^^^^^^^^^...
    Linking a ...
    
[/code]

コンパイルエラーにしたい場合は，`-Werror=⟨wflag⟩` を使えそうです．

[code]

    $ ghc -Werror=incomplete-patterns  a.hs
    [1 of 1] Compiling Main             ( a.hs, a.o )
    
    a.hs:7:22: error: [-Wincomplete-patterns, -Werror=incomplete-patterns]
        Pattern match(es) are non-exhaustive
        In a case alternative: Patterns not matched: (Qrcode _)
      |
    7 | getBarcodeString x = case x of
      |                      ^^^^^^^^^...
    
[/code]


CC BY-SA 4.0
2020-08-29T12:33:19.443
69971
2020-08-29T12:44:07.167
2020-08-29T12:44:07.167
2901
2901
69970
answer