在值构造函数上指定不变量
考虑以下情况
data Predicate = Pred Name Arity Arguments
type Name = String
type Arity = Int
type Arguments = [Entity]
type Entity = String
这将允许创建
Pred "divides" 2 ["1", "2"]
Pred "between" 3 ["2", "1", "3"]
“非法”,但也
Pred "divides" 2 ["1"]
Pred "between" 3 ["2", "3"]
允许“非法”,因为元数与参数列表的长度不匹配。
如果不使用这样的函数
makePred :: Name -> Arity -> Arguments -> Maybe Predicate
makePred n a args | a == length args = Just (Pred n a args)
| otherwise = Nothing
并且只从 Predicate 模块导出 makePred,有没有办法 强制值构造函数的正确性?
Consider the following
data Predicate = Pred Name Arity Arguments
type Name = String
type Arity = Int
type Arguments = [Entity]
type Entity = String
This would allow the creation of
Pred "divides" 2 ["1", "2"]
Pred "between" 3 ["2", "1", "3"]
but also the "illegal"
Pred "divides" 2 ["1"]
Pred "between" 3 ["2", "3"]
"Illegal" because the arity does not match the length of the argument list.
Short of using a function like this
makePred :: Name -> Arity -> Arguments -> Maybe Predicate
makePred n a args | a == length args = Just (Pred n a args)
| otherwise = Nothing
and only exporting makePred from the Predicate module, is there a way to
enforce the correctness of the value constructor?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
嗯,简单的答案是从智能构造函数中删除参数。
然后,如果您不从模块中公开
Pred
构造函数并强制您的客户端执行makePred
,您就知道它们将始终匹配,并且您不需要那个难看的也许
。没有直接方法来强制执行该不变量。也就是说,您将无法让
makePred 2 ["a","b"]
进行类型检查,但makePred 2 ["a","b","c"]
不。为此,您需要真正的依赖类型。中间有一些地方可以说服 haskell 使用高级功能(
GADT
s + 幻像类型)来强制执行你的不变量,但是在写出整个解决方案之后,我意识到我并没有真正解决你的问题,并且这些技术并不真正适用于这个问题。一般来说,它们带来的麻烦也多于它们的价值。我会坚持使用智能构造函数。我写了智能构造函数思想的深入描述。事实证明,这是类型验证和运行时验证之间相当令人愉快的中间立场。
Well, the easy answer is to drop the arity from the smart constructor.
Then if you don't expose the
Pred
constructor from your module and force your clients to go throughmakePred
, you know that they will always match, and you don't need that unsightlyMaybe
.There is no direct way to enforce that invariant. That is, you won't be able to get
makePred 2 ["a","b"]
to typecheck butmakePred 2 ["a","b","c"]
not to. You need real dependent types for that.There are places in the middle to convince haskell to enforce your invariants using advanced features (
GADT
s + phantom types), but after writing out a whole solution I realized that I didn't really address your question, and that such techniques are not really applicable to this problem in particular. They're usually more trouble than they are worth in general, too. I'd stick with the smart constructor.I've written an in-depth description of the smart constructor idea. It turns out to be a pretty pleasant middle ground between type verification and runtime verification.
在我看来,如果您希望上述限制是可执行的,那么您应该将 Predicate 创建为一个类,并且每种谓词都有自己的数据类型,即 Predicate 的实例代码>.
这将使您可以在谓词中使用除字符串类型之外的参数。
像这样的东西(未经测试)
这可能会也可能不会解决您的问题,但它肯定是一个值得考虑的强大选择。
It seems to me that, if you want said restrictions to be enforceable, then you should make
Predicate
a class, and each kind of predicate its own data type that is an instance ofPredicate
.This would give you the possibility of having arguments other than String types in your predicates.
Something like this (UNTESTED)
This may or may not solve your issue, but it is certainly a strong option to consider.