เปลี่ยน Warning — Incomplete Patterns เป็น Error

การเขียน pattern matching ด้วยฟังก์ชั่น มีโอกาสที่เราจะประกาศเคสไม่ครบ ซึ่งจะมีผลให้โปรแกรมทำงานผิดพลาดได้ เช่น ตัวอย่างนี้ จะเกิดรันไทม์ error “No match in record selector conValue” เนื่องจากไม่มี pattern ไหน match กับ Noncon ที่ส่งเข้าไปในฟังก์ชั่น whichCon

module Main where
data Con =
Con { conValue :: String }
| Uncon { conValue :: String }
| Noncon

whichCon :: Con -> String
whichCon con = "convalue is " ++ conValue con
main :: IO()
main = do
putStrLn $ whichCon (Con "A")
putStrLn $ whichCon (Noncon) -- error

วิธีแก้ คือ ให้เปลี่ยนจากการเขียน matching ด้วยฟังก์ชั่น มาใช้ case .. of แทน ในกรณีนี้เราสามารถเพิ่ม compilation flag คือ -Werror พร้อมกับ -fwarn-incomplete-patterns ซึ่งจะช่วยให้ compiler เช็คตั้งแต่การคอมไพล์โปรแกรม

$ ghc -Werror -fwarn-incomplete-patterns -hidir Out -odir Out -o Out/App Main.hs
Pattern match(es) are non-exhaustive
In a case alternative: Patterns not matched: Noncon

เราสามารถใส่ flag ไว้ที่ header ของไฟล์ ก็ได้

{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
{-# OPTIONS_GHC -Werror #-}
module Main where
data Con =
Con { conValue :: String }
| Uncon { conValue :: String }
| Noncon

whichCon :: Con -> String
whichCon con = case con of
Con c -> "convalue is " ++ c
Uncon c -> "convalue is " ++ c
-- Noncon -> "..."
main :: IO()
main = do
putStrLn $ whichCon (Con "A")
putStrLn $ whichCon (Noncon)

เนื่องจาก ไม่มีวิธีบังคับให้คอมไพล์ fail กรณีที่เขียนเคสไม่ครบ การใช้ -fwarn-incomplete-patterns เป็นเพียงการเปิด warning ขึ้นมาเท่านั้น เราจึงต้องเพิ่ม -Werror เพื่อสั่งให้ compiler เปลี่ยน warning ทุกกรณีให้เป็น error รวมทั้งกรณีของ incomplete patterns ด้วย

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.