简体   繁体   English

在List的元素上定义约束函数?

[英]Define Function with Constraint on List's Elements?

How can I define a function with the following signature, 如何使用以下签名定义函数,

f :: [Int???] -> [Int]
f xs = _ -- what I do with xs doesn't matter for the question

where a is a List of Int 's 其中aInt的列表

such that the first argument's inputs, ie list elements, must be >= 0 , but <= 5 at compile-time? 这样第一个参数的输入(即列表元素)必须>= 0 ,而在编译时<= 5

In other words, 换一种说法,

f [6] would fail to compile. f [6]将无法编译。

How about: 怎么样:

f :: [Int] -> [Int]
f = filter (\x -> x >= 0 && x <= 5)

Or do you want to enforce the bounds on the type (dependent types)? 还是要对类型(相关类型)强制执行边界?

If you want to restrict the range of the Int that is allowed you are probably better of using a smart constructor . 如果要限制允许的Int范围,最好使用智能构造函数 Have a look here . 在这里看看。 The idea is that you create your own datatype and your own custom constructor: 这个想法是您创建自己的数据类型和自己的自定义构造函数:

newtype Range0_5 = Range0_5 { unRange :: Int }

makeRange0_5 :: Int -> Maybe Range0_5
makeRange0_5 x
  | x >= 0 && x <= 5 = Just $ Range0_5 x
  | otherwise        = Nothing

If you make a smart constructor , it is important to not expose it to the user of the module. 如果您创建了一个聪明的构造函数 ,那么不要将其暴露给模块的用户就很重要。 This can be done by simply not exporting the Range0_5 constructor. 只需不导出Range0_5构造函数即可完成此操作。

However this is not a compile time check. 但是,这不是编译时检查。 Other languages than Haskell might be more appropriate if you really need such a feature. 如果您确实需要这样的功能,则Haskell以外的其他语言可能更合适。

Since the range is fairly small, you could also make a sum type to represent it: 由于范围很小,因此您也可以创建一个求和类型来表示它:

data Range0_5 = Int0 | Int1 | Int2 | Int3 | Int4 | Int5

If the signature is 如果签名是

f :: [Int] -> [Int]

(which was the original form of the question), then it is impossible to enforce your constraint at compile time. (这是问题的原始形式),那么就不可能在编译时强制执行约束。 This follows from the standard diagonalization argument of the Halting problem . 这是从Halting问题的标准对角化论点得出的

Suppose the compiler could detect that 假设编译器可以检测到

f[g x]

should not compile. 不应该编译。 By incorporating the source code of the compiler into g , it could choose the opposite of the compiler's decision. 通过将编译器的源代码合并到g ,它可以选择与编译器决定相反的选项。


Following your comment on Liquid Haskell (which seems like a very interesting project), note the following: 在您对Liquid Haskell (似乎是一个非常有趣的项目)发表评论之后,请注意以下几点:

{-@ type Even = {v:Int | v mod 2 = 0} @-}

{-@ foo :: n:Even -> {v:Bool | (v <=> (n mod 2 == 0))} @-}   
foo   :: Int -> Bool 
foo n = if n^2 - 1 == (n + 1) * (n - 1) then True else foo (n - 1)

LiquidHaskell claims this function is unsafe, because, potentially foo n calls foo (n - 1) . LiquidHaskell声称此函数不安全,因为可能foo n调用foo (n - 1) Note, however, that this will never happen: it will only be called if the relationship n 2 - 1 ≠ (n + 1) (n - 1) , which can never happen. 但是请注意,这绝不会发生:它只能被称为如果关系N 2 - 1≠(N + 1)(N - 1),这可能永远不会发生。

Again, this is not a criticism of the quality of LiquidHaskell, but rather just pointing out that it, too, cannot solve Halting Problem like issues. 再次,这不是对LiquidHaskell质量的批评,而是仅仅指出它也不能解决类似问题的停止问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM