4

Haskell中函数定义中的括号对于参数的数据类型有什么意义。

例如:

doStuff Name -> Age -> String
doStuff (NameConstr a) (AgeConstr b) = "Nom: " ++ a ++ ", age: " ++ b

事先在某处定义以下内容:

data Name = NameConstr String
data Age = AgeConstr Integer

函数参数 a 和 b 是否可以以不需要括号的方式捕获?

仅供参考,我正在努力:

而且我似乎还无法掌握这个更精细的细节。

4

3 回答 3

7

如果没有括号,该函数将被视为具有四个参数。不过,我想不出省略括号会导致歧义的反例。

如果需要,可以按如下方式重新定义类型:

data Name = NameConstr { getName :: String  }
data Age  = AgeConstr  { getAge  :: Integer }

这样你的功能就可以变成:

doStuff n a = "Nom: " ++ getName n ++ ", age: " ++ show (getAge a)

(固定最后一部分;a是一个Integer并且不能连接到一个字符串)

于 2013-04-14T08:33:12.997 回答
4

实际上,完全可以在没有括号的情况下为(甚至嵌套的)模式解析简单的语法。假设这样一个:

<PAT>  ::= <WILDCARD> | <VAR> | <CON0> | <CON1> <PAT> | <CON2> <PAT> <PAT> ...
<VAR>  ::= <LNAME>
<CON*> ::= <UNAME>
<WILD> ::= "_"

其中 LNAME 是以小写字母开头的名称,而 UNAME 是以大写字母开头的名称。在解析时,我们应该查找构造函数名称,以便找出它的数量。然后我们可以使用arity信息解析构造函数字段。但是这种查找可能会使解析本身变得非常复杂并减慢速度。Haskell 有更复杂的模式(视图模式、“as”模式、记录、具有任意固定性的中缀构造函数等),省略括号会导致歧义。

尽管还有另一个理由不这样做。考虑以下代码:

data Bar = Bar Int
data Foo = Foo Int

libFunction Foo a Bar b = a + b
someUse bar foo = libFunction foo bar

接下来想象我们稍微改变一下数据类型:

data Bar = Bar
data Foo = Foo Int Bar Int

修改后的代码可能仍会进行类型检查,但函数不会像我们预期的那样。这不是一个真实世界的例子,但尽管如此。由于 Haskell 有类型类,因此很难找出我们哪里出错了。

换句话说:我们可以降低错误消息的质量,parens 可以保护我们免受更改后的意外行为。

于 2013-04-14T10:41:28.813 回答
1

这有点傻,但在这种情况下,实际上有一种方法可以避免使用括号:

doStuff :: Name -> Age -> String
NameConstr a `doStuff` AgeConstr b = "Nom: " ++ a ++ ", age: " ++ b

这与定义中缀运算符的方式完全相同,并且在定义非运算符标识符时使用反引号对非运算符标识符进行中缀化的效果与在应用它时一样好。

不过,我不建议您实际使用您不希望在反引号中缀样式中使用的函数来执行此操作。

于 2013-04-16T16:22:13.350 回答