类型签名[...]缺乏附带的绑定

时间:2015-11-09 10:50:07

标签: haskell

为什么我在以下程序中遇到“绑定”错误?

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:
The type signature for ‘wheels’ lacks an accompanying binding

aufgabe1.lhs:7:3:
The type signature for ‘cars’ lacks an accompanying binding

我怎样摆脱它?

2 个答案:

答案 0 :(得分:8)

缺少什么绑定?

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

string carpark(int wheels, int cars);

然而,Haskell并不像这样工作。如果你写

wheels :: Int

在您的文档中,您告诉编译器值wheels将具有类型Int。编译器现在需要某个定义。这个定义 - 它的绑定 - 缺失了。 wheels类型已知,但不知道 wheels应该绑定

如果您要添加

wheels = 1 * 2 + 12312

编译器不会再抱怨该特定绑定了。

实际问题是什么?

正如我上面所述,你想指定carpark的参数类型,对吧?但是,您的结论是指定 carpark类型:

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,如果数字是奇数,则返回"<x> is odd";如果数字是偶数,则返回"<x> is even",其中<x>应该是数字,例如

    whatNumberId 123 == "123 is odd"
    

这两个练习都可以帮助您完成原始任务。

答案 1 :(得分:1)

Zeta的回答已经完成,但我想提出另一个观点,遗憾的是这不适合评论。

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

对Haskell中的代码的这种尝试有点类似于C中的以下代码片段:

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

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

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

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

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