由于Haskell被懒惰地评估,为什么这段代码不起作用?

una*_*der 1 haskell lazy-evaluation

--defining function
safeHead :: [a] -> Maybe a
safeHead [] = Nothing
safeHead (x:_) = Just x

--calling function
safeHead (4:5:3:[]:[])
Run Code Online (Sandbox Code Playgroud)

当我使用参数(4:5:3:[]:[])调用safeHead时,模式仅计算参数以查看它是否为空或是否有头.因此,尽管无意义的位"[]:[]"它不应该抛出错误,因为这部分甚至没有被评估.

Wil*_*sem 9

它不应该抛出错误,因为甚至没有评估这部分.

它没有被评估的事实是无关紧要的.Haskell是一种静态类型语言,编译器会检查类型.它不必计算结果以便对值进行类型检查:所有函数的输入和输出类型都是已知的(计算良好),并且Haskell编译器验证一个函数的输出类型是否与输入的输入相同被调用以处理该输出的函数.

类型检查在编译时完成,并且Haskell编译器不是延迟的(在生成二进制文件之前它执行这些检查的意义上,不仅仅是在运行代码之前).编译器急切地检查类型并保证程序从类型系统的角度来看是敏感的.

例如,以下表达式将进行类型检查:

1 : 2 : undefined
Run Code Online (Sandbox Code Playgroud)

undefined :: a如果评估它会引发错误.

Haskell允许定义新类型的Numbers,因此您可以创建一个类型类来解析数字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]
Run Code Online (Sandbox Code Playgroud)

所以这里它正在寻找列表元素的类型,并且它发现这些应该是列表,因为[]元素(一个但是最后一个元素),但同时这些应该是Nums,现在它失败了找到这样的类型,因此错误.

我们可以严格地说构造这样一种类型,这样我们就可以以适当的方式使用该函数:

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]
Run Code Online (Sandbox Code Playgroud)