[英]Define Function with Constraint on List's Elements?
如何使用以下签名定义函数,
f :: [Int???] -> [Int]
f xs = _ -- what I do with xs doesn't matter for the question
其中a
是Int
的列表
这样第一个参数的输入(即列表元素)必须>= 0
,而在编译时<= 5
?
换一种说法,
f [6]
将无法编译。
怎么样:
f :: [Int] -> [Int]
f = filter (\x -> x >= 0 && x <= 5)
还是要对类型(相关类型)强制执行边界?
如果要限制允许的Int
范围,最好使用智能构造函数 。 在这里看看。 这个想法是您创建自己的数据类型和自己的自定义构造函数:
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
如果您创建了一个聪明的构造函数 ,那么不要将其暴露给模块的用户就很重要。 只需不导出Range0_5
构造函数即可完成此操作。
但是,这不是编译时检查。 如果您确实需要这样的功能,则Haskell以外的其他语言可能更合适。
由于范围很小,因此您也可以创建一个求和类型来表示它:
data Range0_5 = Int0 | Int1 | Int2 | Int3 | Int4 | Int5
如果签名是
f :: [Int] -> [Int]
(这是问题的原始形式),那么就不可能在编译时强制执行约束。 这是从Halting问题的标准对角化论点得出的 。
假设编译器可以检测到
f[g x]
不应该编译。 通过将编译器的源代码合并到g
,它可以选择与编译器决定相反的选项。
在您对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声称此函数不安全,因为可能foo n
调用foo (n - 1)
。 但是请注意,这绝不会发生:它只能被称为如果关系N 2 - 1≠(N + 1)(N - 1),这可能永远不会发生。
再次,这不是对LiquidHaskell质量的批评,而是仅仅指出它也不能解决类似问题的停止问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.