我正在尝试使用Haskell中的模式匹配来定义xor
:
(xor) :: Bool -> Bool -> Bool
True xor False = True
False xor True = True
True xor True = False
False xor False = False
但是这会产生错误:
Invalid type signature: (xor) :: Bool -> Bool -> Bool
Should be of form <variable> :: <type>
我很困惑为什么会抛出这个错误。此外,如果我用xor
之类的内容替换&&
,则脚本加载正常。
答案 0 :(得分:15)
只有运算符应该包含在类型签名的括号中,例如
(&&) :: Bool -> Bool -> Bool
普通函数应在没有的情况下编写,
xor :: Bool -> Bool -> Bool
并且在定义的等式中,你必须将它括在反引号中,
True `xor` True = False
如果您想使用中缀表示法来定义它。如果没有反引号,可以使用前缀表示法
来定义它xor True False = True
但请注意
xor
是来自Bits
类的函数,因此将其用于Bool
可能会出乎意料xor ≡ (/=)
答案 1 :(得分:8)
Haskell区分标识符和运算符符号。标识符是字母数字加'
,并且是有效的条款;如果标识符prefix
具有函数类型,则可以将其称为prefix arg1 arg2
。运算符名称是符号序列,称为arg1 !&$ arg2
。 1 但有时,您希望使用标识符作为中缀运算符或将中缀运算符视为标识符。因此,如果您使用`
s包围任何前缀函数名称,它将成为运算符,您可以(必须)将其用作中缀:arg1 `prefixFunc` arg2
。相反,如果在括号中包装一个中缀运算符名称,它在语法上就会变得有效,因此可以用前缀形式调用:(!&$) arg1 arg2
。 2
在声明变量的类型签名时,您需要将变量的名称作为标识符。 3 对于像{{这样的普通函数名称1}},这只是名字;对于像xor
这样的运算符,如上所述,将其包装在括号中,这就是编写&&
的原因。因此,你要写
(&&) :: Bool -> Bool -> Bool
请注意,我必须进行两项更改。如果你在定义行中省略了反引号,那就好像你试图进行模式匹配一样:xor :: Bool -> Bool -> Bool
True `xor` False = True
False `xor` True = True
True `xor` True = False
False `xor` False = False
看起来像一个带有两个参数的构造函数,而True
将是第一个。 4
(另外,只是为了踢,更短的定义:xor
: - ))
1 词汇结构位于§2.4
2 表达式结构位于§3.2。
3 类型签名的结构位于§4.4.1,指的是§3.2中 var 的定义。
4 绑定的结构在§4.4.3。