【问题标题】:Why do my top level functions need signatures in Haskell?为什么我的顶级函数需要在 Haskell 中签名?
【发布时间】:2013-10-28 16:35:55
【问题描述】:

GHC 警告我在顶层没有函数签名。我不明白为什么我需要它们。提供它们的问题是它们非常复杂,就像这个(自动生成的):

applyValue :: forall t t1 t2 t3 t4.
                (t2 -> t)
                -> (t2 -> t3 -> t4 -> t1) -> t2 -> t3 -> t4 -> (t -> Bool) -> [t1]

那我为什么还要麻烦添加它们呢?

函数本身:

applyValue getValueAt stitchAndMove at fabric mark matchAt =
   if matchAt (getValueAt at)
   then [stitchAndMove at fabric mark]
   else []

【问题讨论】:

  • 您是否启用了任何扩展?
  • 我们可以看看一些代码吗?
  • 如果发生这种情况是因为您使用-Wall 进行编译,您可以使用-fno-warn-missing-signatures。不将它们排除在外被认为是一种好习惯 - 请参阅 Daniel Wagner 的回答了解原因。

标签: haskell


【解决方案1】:
  • 作为机器可检查文档的一种形式。如果您认为该类型是正确的类型,则将其放在那里会要求编译器在以后不可避免的重构会话中再次检查您是否没有使用自己的接口。
  • 作为人类可读的文档。尽管正如您所观察到的,当您注意到自己正在编写一个糟糕的机器生成类型时,可能是时候考虑需要哪些(类型级别的)抽象来使其具有人类可读性。
  • 用于黑线鳕。 Haddock cmets 附加到类型签名,而不是绑定,因此如果您遗漏类型签名,您精心编写的文档将被忽略。
  • 为了改进错误消息和 ghci 查询结果:尽管类型变量的实际名称并不重要,但 GHC 会尽量保留用户提供的名称。像(node -> Bool) -> (edge -> Bool) -> (graph -> Bool) 这样的东西比(t1 -> Bool) -> (t2 -> Bool) -> (t3 -> Bool) 更易读,尽管它们是等价的。

【讨论】:

  • 你的观点很有道理,不过我还有一个简单的问题,有没有办法重用签名块,比如我有一个长而复杂的函数 f1 的签名,现在 f2 需要 f1,所以这是关于 f2 + 无论 f1 是什么的一切。我想知道是否可以通过将签名 f1 分配给某些名称(类型?)来节省一些工作,并在定义 f2 的签名时通过该名称引用它。谢谢
  • @AlekseyBykov 是的,这就是 type 别名的作用。您可以在报告或您最喜欢的教程中了解它们。
  • 即使您不关心文档或错误消息,有时也需要签名。有时,您想要的类型类的实例是模棱两可的,因此您需要显式约束它才能编译。
猜你喜欢
  • 2015-01-19
  • 2018-06-14
  • 2019-04-07
  • 2015-10-31
  • 2012-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
相关资源
最近更新 更多