haskell ADT中的类型安全命名字段

时间:2014-10-18 12:12:22

标签: haskell

有一个很常见的问题很容易与haskell有关。描述它的代码片段是这样的:

data JobDescription = JobOne { n :: Int }
                    | JobTwo
                    | JobThree { n :: Int }
  deriving (Show, Eq)

taskOneWorker :: JobDescription -> IO ()
taskOneWorker t = do
    putStrLn $ "n: " ++ (show $ n t)

main :: IO ()
main = do
  -- this runs ok:
  taskOneWorker (JobOne 10)

  -- this fails at runtime:
  -- taskOneWorker JobTwo

  -- this works, but we didn't want it to:
  -- taskOneWorker (JobThree 10)

我描述了这个问题,本文中可能有解决方案:https://www.fpcomplete.com/user/k_bx/playing-with-datakinds

在这里,在StackOverflow上,我想问你 - 这个问题的最佳解决方案是什么,使用哪些工具和哪些文档?

2 个答案:

答案 0 :(得分:2)

我建议使用PrismPrism _JobOne代表Int构造函数中的JobOne值。在taskOneWorker中,我们使用^?进行查找。值t确实是JobOne构造函数,其参数在Just中返回,或者它不是JobOne构造函数,我们返回Nothing }。

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data JobDescription = JobOne { n :: Int }
                    | JobTwo
                    | JobThree { n :: Int }
  deriving (Show, Eq)
$(makePrisms ''JobDescription)

taskOneWorker :: JobDescription -> IO ()
taskOneWorker t = do
  case t ^? _JobOne of
    Just n  -> putStrLn $ "n: " ++ show n
    Nothing -> putStrLn "Not a JobOne"
               -- Or 'return ()' if you want to ignore these cases

main :: IO ()
main = do
  taskOneWorker (JobOne 10)
  taskOneWorker JobTwo
  taskOneWorker (JobThree 10)

-- *Main> main
-- n: 10
-- Not a JobOne
-- Not a JobOne

答案 1 :(得分:-1)

耶;使用像你一样的镜头并抽象出" n"事情变成某种" JobData"对我来说似乎并不太糟糕(甚至可能还不错。)