如何调用可能失败的构造函数,尤其是在实现' Read'和'任意'?

时间:2015-11-15 20:03:22

标签: haskell error-handling exception-handling quickcheck

我有一个"公共保险箱"可能会因(可能提供信息)错误而失败:

data EnigmaError = BadRotors
                 | BadWindows
                 | MiscError String

instance Show EnigmaError where
  show BadRotors = "Bad rotors"
  show BadWindows = "Bad windows"
  show (MiscError str) = str

configEnigma :: String -> String -> String -> String -> Except EnigmaError EnigmaConfig
configEnigma rots winds plug rngs = do
        unless (and $ [(>=1),(<=26)] <*> rngs') (throwError BadRotors)
        unless (and $ (`elem` letters) <$> winds') (throwError BadWindows)
        -- ...
        return EnigmaConfig {
                components = components',
                positions = zipWith (\w r -> (mod (numA0 w - r + 1) 26) + 1) winds' rngs',
                rings = rngs'
        }
    where
        rngs' = reverse $ (read <$> (splitOn "." $ "01." ++ rngs ++ ".01") :: [Int])
        winds' = "A" ++ reverse winds ++ "A"
        components' = reverse $ splitOn "-" $ rots ++ "-" ++ plug

但目前还不清楚我应该如何调用它,特别是(特别是)实现ReadArbitrary(对于QuickCheck)。

对于前者,我可以达到

instance Read EnigmaConfig where
        readsPrec _ i = case runExcept (configEnigma c w s r) of
            Right cfg  -> [(cfg, "")]
            Left err -> undefined
          where [c, w, s, r] = words i

但这似乎最终隐藏了err中可用的错误信息;而对于后者,我被困在

instance Arbitrary EnigmaConfig where
        arbitrary = do
                nc <- choose (3,4)  -- This could cover a wider range
                ws <- replicateM nc capitals
                cs <- replicateM nc (elements rotors)
                uk <- elements reflectors
                rs <- replicateM nc (choose (1,26))
                return $ configEnigma (intercalate "-" (uk:cs))
                                      ws
                                      "UX.MO.KZ.AY.EF.PL"  -- TBD - Generate plugboard and test <<<
                                      (intercalate "." $ (printf "%02d") <$> (rs :: [Int]))

因预期和实际类型不匹配而失败:

  

预期类型:Gen EnigmaConfig   实际类型:Gen(变形金刚-0.4.2.0:Control.Monad.Trans.Except.Except Crypto.Enigma.EnigmaError EnigmaConfig)

如果(#&#34;公共安全&#34;)构造函数可能会失败,尤其是在为我的班级实现ReadArbitrary时使用它时,我该如何调用它?

1 个答案:

答案 0 :(得分:2)

Read类型类表示成功列表的解析(失败与没有成功相同);所以而不是undefined你应该返回[]。至于丢失有关错误的信息:这是真的,readsPrec的类型意味着你无法做多少。如果你真的,真的想[注意:我认为你不应该这样]你可以在Except EnigmaError EnigmaConfig周围定义一个newtype包装器,并给一个成功解析配置错误的Read实例。

对于Arbitrary,您有几个选择。一种选择是所谓的拒绝抽样; e.g。

arbitrary = do
    -- ...
    case configEnigma ... of
        Left err -> arbitrary -- try again
        Right v  -> return v

您可能还会将Arbitrary实例视为内部API的一部分,并使用不安全的内部调用,而不是使用安全的公共API来构建配置。其他选项包括致电errorfail。 (我认为这四个选项大致是偏好顺序 - 拒绝抽样,然后是不安全的内部调用,然后是error,然后是fail - 尽管您的判断可能不同。)