【问题标题】:The type signature […] lacks an accompanying binding类型签名 […] 缺少随附的绑定
【发布时间】:2015-11-09 10:50:07
【问题描述】:

为什么我会在以下程序中出现“绑定”错误?

wheels :: Int

cars :: Int

carpark wheels cars   
  | wheels   == odd      = error wheels "is not even"
  | cars     <= 0        = error cars "is an invalid number"
  | (2*cars) >= wheels   = error "the number of wheels is invalid"
  | wheels   >= (4*cars) = error "the number of wheels is invalid"
  | otherwise            = "There are " (wheels-(2 * cars)) `div` 2 "cars and " (cars - ((wheels - (2 * cars)) div 2)) "motorcycles on the parking lot"

这是错误:

 aufgabe1.lhs:6:3:
“wheels”的类型签名缺少随附的绑定

aufgabe1.lhs:7:3:
“汽车”的类型签名缺少随附的绑定

我怎样才能摆脱它?

【问题讨论】:

  • 您不应该为函数参数编写单独的类型签名。您只需要carPark :: Int -&gt; Int -&gt; String,这是carPark 的类型签名。
  • 当心 - 您需要“toString”方法 showInt 转换为 String 并使用连接运算符 ++ 来组合这些字符串

标签: haskell


【解决方案1】:

缺少哪些绑定?

您的程序有很多问题,但让我们先关注“绑定”问题。您可能习惯于 Pascal 或 C,您必须在参数处指定参数的类型:

string carpark(int wheels, int cars);

但是,Haskell 不是这样工作的。如果你写

wheels :: Int

在您的文档中,您告诉编译器值wheels 将具有Int 类型。编译器现在需要在某处进行定义。这个定义——它是有约束力的——缺失了。 wheels类型是已知的,但不知道 wheels 应该绑定到什么

如果你要添加

wheels = 1 * 2 + 12312

编译器不会再抱怨那个特定的绑定了。

真正的问题是什么?

正如我在上面得出的结论,您想指定carpark 的参数类型,对吗?但是,这得出您指定 carpark's 类型的结论:

carpark :: Int -> Int -> String
carpark wheels cars 
   | -- omitted

这将消除“缺少绑定”错误。

缺少什么?

好吧,在这之后,你仍然会有一个非编译的软件,例如error wheels "is not even" 是无效的。看看error的类型:

error :: String -> a

由于wheels 不是String,因此无法编译。相反,你必须show wheels:

error (show wheels ++ " is not even")

请注意,error (show wheels) " is not even" 会很高兴地编译,但不会给您实际寻找的错误消息,因此请注意括号和字符串连接。

练习

  • 编写一个函数whatNumber,如果数字是奇数则返回“Is Odd”,如果数字是偶数则返回“Is Even”,例如

    whatNumber 2 == "Is Even"
    
  • 编写一个函数whatNumberId,如果数字是奇数,则返回"&lt;x&gt; is odd",如果数字是偶数,则返回"&lt;x&gt; is even",其中&lt;x&gt;应该是数字,例如

    whatNumberId 123 == "123 is odd"
    

这两个练习都可以帮助您完成最初的任务。

【讨论】:

    【解决方案2】:

    Zeta 的回答很完整,但我想再提一点,遗憾的是不适合发表评论。

    wheels :: Int
    cars :: Int
    carpark wheels cars...
    

    这种在 Haskell 中的代码尝试有点类似于以下 C 中的代码 sn-p:

    int wheels;
    int cars;
    char* carpark(wheels, cars) { ... }
    

    类比在哪里?在这两种情况下,wheels(或cars)的第一次和第二次出现指的是不同的对象。第一个是全局变量,第二个是函数的形参。

    carpark里面,wheels表示函数的形参;由于名称隐藏,全局 wheels 不可用。请注意,在 C99 及更高版本中,此代码将是非法的,因为 carpark 的形式参数未指定类型。全局wheels 被赋予int 类型这一事实毫无意义,因为wheelscarpark 中的wheels 无关。

    这些标识符范围的一般概念也适用于 Haskell。声明wheels :: Int 在其作用域(可能是模块作用域)声明了一个值,而carpark wheels cars 对嵌套作用域中的另一个值使用相同的名称。您无法访问carpark 正文中的外部wheels,因为它是隐藏的;如果您改为写carpark w c...,您将可以访问外部wheels 和本地w

    最后,虽然在上面的 C sn-p 中缺少 wheelscars 的类型构成错误,但在 Haskell 中我们通常将其留给编译器来推断形式参数的类型。 carpark 本身就是一个值,所以它有一个类型。如果我们将类型声明为carpark :: Int -&gt; Int -&gt; String,编译器会推断,在以carpark wheels cars... 开头的定义中,wheels 不能是Int 类型。

    【讨论】:

    • 我很确定我见过一种语言,您可以先编写参数及其类型,然后再编写实际函数。但我不记得它的名字了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 2022-08-21
    相关资源
    最近更新 更多