Haskell 如何调用可能失败的构造函数,特别是在实现“Read”和“arbitral”时?
我有一个公共保险箱,可能会出现潜在的信息错误:Haskell 如何调用可能失败的构造函数,特别是在实现“Read”和“arbitral”时?,haskell,error-handling,exception-handling,quickcheck,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 co
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
但这似乎最终隐藏了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
实际类型:发电机变压器-0.4.2.0:Control.Monad.Trans.Exception.Exception.Crypto.Enigma.EnigmaError EnigmaConfig
当公共安全构造函数可能失败时,特别是在为我的类实现Read和arbitral时,如何调用它?Read typeclass将解析表示为成功列表,失败与否相同;因此,您应该返回[],而不是未定义。至于丢失错误信息:这是真的,readsPrec的类型意味着你对此无能为力。如果你真的想[注意:我认为你不应该想要这个],你可以在EnigmaError EnigmaConfig之外定义一个新的类型包装器,并给它一个读取实例,该实例成功解析了配置错误
对于武断,你有两个选择。一种选择是所谓的拒绝抽样;e、 g
arbitrary = do
-- ...
case configEnigma ... of
Left err -> arbitrary -- try again
Right v -> return v
您也可以将任意实例视为内部API的一部分,使用不安全的内部调用,而不是使用安全、公共API来构造配置。其他选项包括调用错误或失败。我认为这四个选项大致上是优先顺序-拒绝抽样,然后是不安全的内部调用,然后是错误,然后失败——尽管您的判断可能有所不同。
因为Read应该完全失败,并且因为要通知,而不是未定义或[],错误显示错误是什么?同样在武断的情况下,因为我只为参数生成有效值,我希望它立即失败,而不是悄悄地尝试另一个;所以error show err而不是任意的?@raxacoricofallapatorius如果你想写一个包含信息错误的解析器,你可以自由地;你就是不能,不应该叫它读。啊,我明白了。我在docs for Read中遗漏了这一点:无论是什么原因,Read都应该失败,没有解析,readsPrec应该返回[],正如您所说的:。这对用户imv来说太糟糕了,因为信息丢失了;但这些就是我猜想的规则。不过,对于任意EnigmaConfig,如果我生成的参数都是有效的,我当然不想做这么酷的拒绝采样:我只是想失败,我想:这将是一个真正的编码错误。请注意,readsPrec中的信息丢失,以及其他可能的情况,如果构造器出现错误而失败,则可以避免此问题–请参阅我最近对的评论。arbitrary = do
-- ...
case configEnigma ... of
Left err -> arbitrary -- try again
Right v -> return v