我有一个"公共保险箱"可能会因(可能提供信息)错误而失败:
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
但目前还不清楚我应该如何调用它,特别是(特别是)实现Read
和Arbitrary
(对于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;)构造函数可能会失败,尤其是在为我的班级实现Read
和Arbitrary
时使用它时,我该如何调用它?
答案 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来构建配置。其他选项包括致电error
或fail
。 (我认为这四个选项大致是偏好顺序 - 拒绝抽样,然后是不安全的内部调用,然后是error
,然后是fail
- 尽管您的判断可能不同。)