我非常依赖haskell的类型系统来避免错误,并且正在研究它是否也可用于确保(弱?)形式的代码正确性。
我想到的代码正确性的形式如下:
如果f :: a -> b
保证为f
类型的任何输入生成b
类型的输出,则函数a
是正确的。对于众所周知的函数头(head:: [a] -> a
),这显然是失败的。
我知道类型系统无法保证这种形式的正确性的一种方式是代码使用错误(error :: Char -> a
)。错误函数几乎覆盖了整个类型系统,因此我希望避免使用此函数,除非明确指出。
我的问题是双重的:
除了错误之外还有哪些其他函数(或haskell片段)是Haskell类型系统的例外?
更重要的是,有没有一种方法禁止在Haskell模块中使用这些函数?
非常感谢!
答案 0 :(得分:5)
您可以编写自己不会产生值的函数。考虑以下功能:
never :: a -> b
never a = never a
它无法终止,因此它被认为是值_|_
(发音为bottom)。 All types in Haskell are actually the sum of the type and this special value
您还可以编写仅部分定义的函数,例如
undefinedForFalse :: Bool -> Bool
undefinedForFalse True = True
undefinedForFalse False
是undefined
,这是一个特殊值,在语义上等同于_|_
,除了运行时系统可以停止执行,因为它知道它永远不会完成。
error
也是特殊函数,其结果始终在语义上等同于_|_
,它告诉运行时系统它可以停止执行,知道它永远不会完成,以及信息性的错误消息。< / p>
Haskell无法证明类型永远不会取值_|_
,因为类型总是可以取值_|_
。永远不会是_|_
的值称为“总计”。在有限的时间内总是产生_|_
以外的值的函数称为“总函数”。可以证明这一点的语言称为“总语言”或“total functional programming languages”。如果他们能够证明这种语言中的所有类型,那么他们必然是图灵不完整的。
答案 1 :(得分:1)
不可能证明任何任意函数都会在图灵完整语言中产生一个值。当然,您可以使用某些特定功能。 Cirdec很好地介绍了这一点,但我想指出一些关于使用类型系统保证(某种程度)正确性的事情。
相关主题是参数化:给定多态类型签名的事实通常只有一组有限的可能实现(如果我们排除error
,undefined
和其他类似的东西)。
其中一个例子是(a -> b) -> a -> b
。实际上只有一种可能的功能实现。
另一个例子是,从某个类型A到某个类型B和函数f
给定r :: [a] -> [a]
,可以显示r . map f = map f . r
。这被称为&#34;自由定理&#34;为map
。许多其他多态类型也有自由定理。
A(有时更有用)结果是,如果您能证明函数mapper :: (a -> b) -> F a -> F b
服从法律mapper id = id
,则可以显示mapper f . mapper g = mapper (f . g)
。此外,这将是fmap
类型的F
实施,因为这两个法律是Functor
法律。这个特别的&#34;融合&#34;法律可用于优化目的。
来源:免费的定理! http://ttic.uchicago.edu/~dreyer/course/papers/wadler.pdf