简体   繁体   English

Haskell数据类型函数参数

[英]Haskell data type function parameter

What is the significance of the parenthesis in a function definition in Haskell with respect to the data type of parameters. 对于参数的数据类型,Haskell中的函数定义中的括号有什么意义。

For example: 例如:

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

with the following defined somewhere beforehand: 预先在某处定义以下内容:

data Name = NameConstr String
data Age = AgeConstr Integer

Could the function parameters a and b be captured in a way that negates the need for parenthesis here? 功能参数a和b是否可以在这里取消对括号的需要?

FYI, I'm working through: 仅供参考,我正在努力:

and I just can't seem grasp this finer detail yet. 我似乎无法掌握这个更精细的细节。

Without parentheses, the function would be deemed to have four parameters. 没有括号,该函数将被视为具有四个参数。 I can't think of a counterexample where omitting brackets would lead to ambiguity, though. 我想不出一个反例,即省略括号会导致含糊不清。

If you want, you can redefine your types as follows: 如果需要,您可以按如下方式重新定义类型:

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

so that your function can become: 这样你的功能就可以变成:

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

(fixed the last part; a is an Integer and cannot be concatenated to a string) (修复了最后一部分; a是一个Integer ,不能连接成一个字符串)

Indeed, it's possible to parse simple grammar for (even nested) patterns without parens at all. 实际上,有可能为(甚至嵌套的)模式解析简单的语法而根本没有parens。 Suppose such one: 假设这样一个:

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

where LNAME is names that starts with lowercase letter and UNAME starts with uppercase letter. 其中LNAME是以小写字母开头的名称,UNAME以大写字母开头。 While parsing we should look up constructor name so we can find out its arity. 解析时我们应该查找构造函数名称,以便我们找到它的arity。 Then we can parse constructor fields using arity information. 然后我们可以使用arity信息解析构造函数字段。 But this lookup might significant complicate and slow down parsing itself. 但是这种查找可能会使解析本身变得复杂化并减慢其速度。 Haskell has much more complex patterns(view patterns, "as" patterns, records, infix constructors with arbitrary fixity, etc) and omitting parens can lead to ambiguity. Haskell具有更复杂的模式(视图模式,“作为”模式,记录,具有任意固定性的中缀构造函数等)并且省略parens可能导致模糊性。

Though there is another reason not to do that. 虽然还有另一个原因不这样做。 Consider the following code: 请考虑以下代码:

data Bar = Bar Int
data Foo = Foo Int

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

Next imagine we change datatypes a bit: 接下来想象我们稍微更改数据类型:

data Bar = Bar
data Foo = Foo Int Bar Int

Modified code might still typecheck, but the function will do not that we expect. 修改后的代码可能仍然存在类似问题,但该功能将不符合我们的预期。 Not a real world example but nevertheless. 虽然不是现实世界的例子。 And since Haskell have type classes it can be pretty hard to find out where we get something wrong. 而且由于Haskell有类型类,因此很难找到出错的地方。

In other words: we can loose quality of error messages and parens defends us from unexpected behaviour after changes. 换句话说:我们可以放松错误消息的质量,而且parens可以防止我们在更改后出现意外行为。

It's slightly silly, but in this case there is actually a way to avoid parentheses: 它有点傻,但在这种情况下,实际上有一种方法可以避免使用括号:

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

This is exactly the same way you define an infix operator, and using backticks to infix-ify a non-operator identifier works just as well when defining it as when applying it. 这与定义中缀运算符的方式完全相同,并且使用反引号作为infix-ify非运算符标识符在将其定义为应用时也同样有效。

I don't recommend actually doing this with functions you don't expect to be used in backtick-y infix style, though. 不过,我不推荐使用你不希望在backtick-y中缀风格中使用的函数实际执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM