如何验证Haskell"公共安全"构造函数的参数?

oro*_*ome 1 validation haskell assertions python-2.7

在我的Python包中,我有一个函数,我用它来创建我的类的验证实例,类似于

@staticmethod
def config_enigma(rotor_names, window_letters, plugs, rings):

    comps = (rotor_names + '-' + plugs).split('-')[::-1]
    winds = [num_A0(c) for c in 'A' + window_letters + 'A'][::-1]
    rngs = [int(x) for x in ('01.' + rings + '.01').split('.')][::-1]

    assert all(name in rotors for name in comps[1:-1])
    assert comps[-1] in reflectors
    assert len(rngs) == len(winds) == len(comps)
    assert all(1 <= rng <= 26 for rng in rngs)
    assert all(chr_A0(wind) in LETTERS for wind in winds)

    #...
Run Code Online (Sandbox Code Playgroud)

我想在Haskell中强制执行相同的行为.但是以相同的方式执行此操作 - 使用断言 - 不起作用,因为Haskell断言通常被禁用(除非设置了某些编译器标志).例如,在类似的东西

configEnigma rots winds plug rngs =
    assert ((and $ (==(length components')) <$> [length winds', length rngs']) &&
            (and $ [(>=1),(<=26)] <*> rngs') &&
            (and $ (`elem` letters) <$> winds') &&
            (and $ (`M.member` comps) <$> tail components'))
    -- ...
    where
        rngs' = reverse $ (read <$> (splitOn "." $ "01." ++ rngs ++ ".01") :: [Int])
        winds' = "A" ++ reverse winds ++ "A"
        components' = reverse $ splitOn "-" $ rots ++ "-" ++ plug
Run Code Online (Sandbox Code Playgroud)

不能依赖于工作,因为断言将在大多数情况下被删除.

什么是强制所有实例在Haskell中验证(使用"公共安全"构造函数)的惯用且可靠的方法?

Dan*_*ner 5

通常的做法是明确表达失败.例如,有人可能会写

configEnigma :: ... -> Maybe ...
configEnigma ... = do
    guard (all (((==) `on` length) components') [winds', rngs'])
    guard (all (inRange (1,26)) rngs')
    guard (all (`elem` letters) winds')
    guard (all (`M.member` comps) (tail components'))
    return ...
    where
    ...
Run Code Online (Sandbox Code Playgroud)

你甚至可以考虑从升级MaybeExcept Error了一些自定义的类型Error,传达给调用者什么是去建设过程中出错.然后guard,您可以使用以下结构:

    unless (all (inRange (1,26)) rngs') (throwError OutOfRange)
Run Code Online (Sandbox Code Playgroud)

呼叫者configEnigma必须表达如何处理故障.对于Maybe,这看起来像

case configEnigma ... of
    Just v  -> -- use the configured enigma machine v
    Nothing -> -- failure case; perhaps print a message to the user and quit
Run Code Online (Sandbox Code Playgroud)

Except你同时获得有关出错的信息:

case runExcept (configEnigma ...) of
    Right v  -> -- use the configured enigma machine v
    Left err -> -- failure case; tell the user exactly what went wrong based on err and then quit
Run Code Online (Sandbox Code Playgroud)