为什么在Haskell中写类型声明?

Vla*_*sky 24 haskell types type-inference

我是Haskell的新手,我试图理解为什么需要编写类型声明.由于Haskell有类型推断,我什么时候需要第一行?GHCI似乎生成正确的输出我用':t'

到目前为止,我发现的唯一一个似乎需要声明的例子如下.

maximum' :: (Ord a) => [a] -> a  
maximum' = foldr1 max
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加"-XNoMonomorphismRestriction",则不再需要标志声明.是否存在类型推断不起作用且需要指定类型的特定情况?

由于我可能在类型声明中有错误并且没有直接的好处,我宁愿不写它.我刚刚开始学习Haskell,所以如果我错了请纠正我,因为我想养成良好的习惯.

编辑:事实证明,类型推断是真实世界Haskell书中的一个双刃剑部分,对这个主题进行了很好的讨论.

Joh*_*iss 28

  • 当你有大型Haskell程序时,拥有类型签名通常会为编译器提供更好的错误消息
  • 有时您可以从其名称和签名中派生出函数的功能
  • 通常使用类型签名可以更好地理解函数,例如,如果您使用currying
  • 甚至编写程序变得更容易,我经常从类型签名开始,大多数函数声明为undefined.一切都编译我知道我的想法似乎不太糟糕.然后我继续undefined用真实代码替换

  • 一个额外的 - 有时定义一个比推断的更严格的类型是有用的.这可能与您的第一点有些相关 - 通过限制类型,编译器可以确定函数不适合特定情况并拒绝使用它,而不是反正使用它并导致更间接且难以诊断错误. (9认同)
  • 更好的错误消息是一个很大的优点,可读性也是如此.这是有道理的.谢谢. (5认同)

alt*_*ive 15

考虑read "5".Haskell怎么知道这种类型read "5"?它不能,因为没有办法解决操作的结果,因为read被定义为(Read a) => String -> a.a不依赖于字符串,因此它必须使用上下文.

然而,通常上下文是类似的Ord,Num因此无法确定.这不是单态限制,而是另一种永远无法正确处理的情况.

例子:

不起作用:

read "0.5"
putStrLn . show . read $ "0.5"
Run Code Online (Sandbox Code Playgroud)

工作:

read "0.5" :: Float
putStrLn . show . (read :: String -> Float) $ "0.5"
Run Code Online (Sandbox Code Playgroud)

这些是必要的,因为默认情况Show下,如果我没记错的话,是Int.

  • @Vladimir这不是IO.它纯粹的解析. (3认同)

Dan*_*ton 5

安心.有时确保编译器同意您对函数类型应该是什么的看法是很好的.如果推断的类型没有与您给定的类型统一,那么编译器会对您大喊大叫.熟悉类型系统后,您会发现可选类型签名对您的编码信心非常有利.

  • @Vladimir Bychkovsky:这对于非常通用的函数特别有用,其中错误可能会产生您不想要的有效类型.给出签名意味着类型错误将在声明中找到,而不是在您尝试使用该函数时的其他位置. (2认同)