--defining function
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
--calling function
safeHead (4:5:3:[]:[])
当我使用参数(4:5:3:[]:[])调用safeHead时,模式仅评估参数以查看其是否为空或是否具有头。因此,尽管没有意义的位[[]:[]”,它也不会抛出错误,因为这部分甚至都没有被评估。
答案 0 :(得分:9)
它不会抛出错误,因为这部分甚至都没有评估。
不对其进行评估的事实无关紧要。 Haskell是一种静态类型的语言,编译器会检查类型。不必为了对值进行类型检查而计算结果:所有函数的输入和输出类型都是已知的(计算正确),Haskell编译器会验证一个函数的输出类型与的输入相同。用于处理该输出的函数。
类型检查在编译时完成,Haskell编译器不是惰性的(在某种意义上,它是在生成二进制文件之前而不是在运行之前执行这些检查的)代码)。编译器会急切地检查类型,并从类型系统的角度保证程序是明智的。
例如,以下表达式将进行类型检查:
1 : 2 : undefined
但是undefined :: a
会在评估时引发错误。
Haskell允许定义Num
bers的新类型,因此您可以创建一个将数字4
,5
和3
解析为您自己类型的数字的类型类。严格来说,该类型可以是列表。
但是,如果您对此进行评估,Haskell将找不到要使用的类型,并且会引发错误:
Prelude> safeHead (4:5:3:[]:[])
<interactive>:6:1: error:
• Non type-variable argument in the constraint: Num [t]
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall t. Num [t] => Maybe [t]
因此在这里,它正在寻找列表元素的类型,并且由于[]
元素(最后一个元素),这些元素应该是列表,但同时这些应该是Num
,现在找不到这种类型,因此会出错。
严格来说,我们可以构造这种类型,以便我们可以以适当的方式使用该功能:
Prelude> data A = A deriving Show
Prelude> :{
Prelude| instance Num [A] where
Prelude| (+) = undefined
Prelude| (*) = undefined
Prelude| abs = undefined
Prelude| fromInteger _ = [A]
Prelude| negate = undefined
Prelude| signum = undefined
Prelude| :}
Prelude> :{
Prelude| safeHead :: [a] -> Maybe a
Prelude| safeHead [] = Nothing
Prelude| safeHead (x:_) = Just x
Prelude| :}
Prelude> safeHead (4:5:3:[]:[]) :: Maybe [A]
Just [A]
答案 1 :(得分:3)
需要一些按摩,但是有时您可能会得到ghc来延缓诸如此类的 类型错误,并给出答案。
-- defer.hs
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x
n :: Int
n = []
nonsense :: [Int]
nonsense = (4 : 5 : 3 : n : [])
r :: Maybe Int
r = safeHead nonsense
给出上述文件,如果您使用-fdefer-type-errors
标志将其加载到ghc或ghci中...
$ ghci -fdefer-type-errors defer.hs
defer.hs:6:5: warning: [-Wdeferred-type-errors]
• Couldn't match expected type ‘Int’ with actual type ‘[a0]’
• In the expression: []
In an equation for ‘n’: n = []
|
6 | n = []
| ^^
ghci> r
Just 4
ghci> nonsense !! 3
*** Exception: defer.hs:6:5: error:
• Couldn't match expected type ‘Int’ with actual type ‘[a0]’
• In the expression: []
In an equation for ‘n’: n = []
(deferred type error)
通常,Haskell程序的类型错误是致命的,从而阻止了它们的编译。但是, some 这样的错误可以推迟。这通常不是一个好主意,并且推迟类型错误的功能在可以推迟的程度上受到限制。
因此,为回答您的问题,Haskell并非旨在让类型错误滑动,即使该类型错误实际上并未影响任何实时代码路径。但是,您可以选择加入这种可疑的行为。
答案 2 :(得分:1)
Haskell程序中的每个位都必须具有类型。 预先。
术语(4:5:3:[]:[])
实际上具有类型。
> :t safeHead (4:5:3:[]:[])
safeHead (4:5:3:[]:[]) :: Num [t] => Maybe [t]
> safeHead (4:5:3:[]:[])
<interactive>:10:1:
No instance for (Num [t0]) arising from a use of `it'
In a stmt of an interactive GHCi command: print it
只是缺少实例。
> instance (Num a) => Num [a] where
a + b = a
a - b = a
a * b = a
abs a = a
signum a = a
fromInteger x = [fromInteger x]
> safeHead (4:5:3:[]:[])
Just [4]
it :: Num t => Maybe [t]
数字文字是多态定义,而不是具体值; 4
实际上被读为(fromInteger 4) :: Num a => a
,因此特定的fromInteger
根据其实际具有的特定类型来执行其特定的工作。在这里
four :: Num t => Num [t]
four = fromInteger 4 -- according to our definition, it's
= [fromInteger 4]
事实证明,这毕竟不是一个 complete 废话。 :)