为什么我在以下程序中遇到“绑定”错误?
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
我怎样摆脱它?
答案 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
类型的事实毫无意义,因为wheels
与wheels
中的carpark
无关。
标识符范围的这些一般概念也适用于Haskell。声明wheels :: Int
在其范围内声明了一个值(可能是模块范围),carpark wheels cars
对嵌套范围中的另一个值使用相同的名称。您无法访问wheels
正文中的外部carpark
,因为它已被隐藏;如果您写了carpark w c...
,则可以访问外部wheels
和本地w
。
最后,在上面的C片段中,wheels
和cars
缺少类型构成错误,在Haskell中我们通常会将其留给编译器来推断形式参数的类型。 carpark
本身就是一个值,因此它有一个类型。如果我们将类型声明为carpark :: Int -> Int -> String
,编译器会推断出,在以carpark wheels cars...
开头的定义中,wheels
此处不能是Int
类型。