如何调用可能会失败的构造函数,尤其是在实现' Read'时和'任意&#39 ;? [英] How do I call a constructor that may fail, especially when implementing 'Read' and 'Arbitrary'?

查看:71
本文介绍了如何调用可能会失败的构造函数,尤其是在实现' Read'时和'任意&#39 ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a "public safe" that may fail with a (potentially informative) errors:

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 任意(用于QuickCheck)中.

but it is unclear how I should call this, particularly (and specifically) in implementing Read and Arbitrary (for 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 中可用的错误信息;而对于后者,我被困在

but this seems to end up hiding error information available in err; while for the latter, I'm stuck at

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]))

失败,其预期类型与实际类型不匹配:

which fails with a mismatch between the expected and actual types:

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

Expected type: Gen EnigmaConfig Actual type: Gen (transformers-0.4.2.0:Control.Monad.Trans.Except.Except Crypto.Enigma.EnigmaError EnigmaConfig)

当(公共安全")构造函数可能会失败时,尤其是在为我的课程实现 Read Arbitrary 时,该如何使用呢?>

How do I call a ("public safe") constructor when it may fail, particularly when using it in implementing Read and Arbitrary for my class?

推荐答案

Read 类型类将解析表示为成功列表(失败与没有成功相同);因此,您应该返回 [] ,而不是 undefined .至于丢失有关出了什么问题的信息:是的,并且 readsPrec 的类型意味着您不能为此做太多事情.如果您确实确实想要[注意:我不认为您应该这样做],则可以围绕 EnigmaError EnigmaConfig 以外的对象定义一个新类型包装器,并为它提供一个 Read 实例成功解析了配置错误.

The Read typeclass represents parses as lists of successes (with failures being the same as no successes); so rather than undefined you should return []. As for losing information about what went wrong: that's true, and the type of readsPrec means you can't do much about that. If you really, really wanted to [note: I don't think you should want this] you could define a newtype wrapper around Except EnigmaError EnigmaConfig and give that a Read instance that had successful parses of configuration errors.

对于任意,您有两种选择.一种选择是所谓的拒绝采样.例如

For Arbitrary you have a couple choices. One choice is so-called rejection sampling; e.g.

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

您还可以将任意实例视为内部API的一部分,并使用不安全的内部调用而不是使用安全的公共API来构造您的配置.其他选项包括调用 error fail .(我认为这四个选项大致按优先顺序排列-拒绝采样,然后是不安全的内部调用,然后是 error ,然后是 fail ,尽管您的判断可能有所不同.)

You might also consider an Arbitrary instance to be part of your internal API, and use unsafe, internal calls rather than using the safe, public API for constructing your configuration. Other options include calling error or fail. (I consider these four options to be in roughly preference order -- rejection sampling, then unsafe internal calls, then error, then fail -- though your judgement may differ.)

这篇关于如何调用可能会失败的构造函数,尤其是在实现&amp;#39; Read&amp;#39;时和&amp;#39;任意&amp;#39 ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆