如何阅读语法“Typ{…在haskell }’吗?(复制)

时间:2021-05-27 16:08:22

This question already has an answer here:

这个问题已经有了答案:

While reading library code here I have noticed a really weird looking syntax that I can't make sense of:

在阅读图书馆代码时,我注意到一种非常奇怪的语法,我无法理解:

momenta
    :: (KnownNat m, KnownNat n)
    => System m n
    -> Config n
    -> R n
momenta Sys{..} Cfg{..} = tr j #> diag _sysInertia #> j #> cfgVelocities
    --  ^^^^^^^^^^^^^^^ the syntax in question
  where
    j = _sysJacobian cfgPositions

The relevant definitions of System includes a record { _sysJacobian :: R n -> L m n }, and { cfgVelocities :: R n } is part of the record declaration of Config so I believe I know what the code does, I think the code is quite readable, props to the author.

系统包括一个记录的相关定义{ _sysJacobian:R n - > L m n },{ cfgVelocities:R n }是配置记录声明的一部分,所以我相信我知道什么代码,我觉得非常可读的代码,道具的作者。

The question is: what is this syntax called and how exactly can I use it?

问题是:这个语法叫什么,我该如何使用它?

2 个解决方案

#1


15  

In short: it is an extension of GHC called RecordWildCards.

简而言之:它是GHC的一个扩展,称为RecordWildCards。

In Haskell you can use record syntax to define data types. For example:

在Haskell中,您可以使用记录语法来定义数据类型。例如:

data Foo = Bar { foo :: Int, bar :: String } | Qux { foo :: Int, qux :: Int }

We can then pattern match on the data constructor, and match zero or more parameters, for example:

然后,我们可以对数据构造函数进行模式匹配,并匹配零个或多个参数,例如:

someFunction :: Int -> Foo -> Foo
someFunction dd (Bar {foo=x}) = dd + x
someFunction dd (Qux {foo=x, qux=y}) = dd + x + y

But it can happen that we need access to a large amount (or even all) parameters. Like for example:

但是,我们需要访问大量(甚至所有)参数。例如:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {foo=foo, bar=bar}) = foo
someOtherFunction (Qux {foo=foo, qux=qux}) = foo + qux

In case the number of parameters is rather large, then this becomes cumbersome. There is an extension RecordWildCards:

如果参数的数量相当大,那么这将变得很麻烦。有一个扩展记录通配符:

{-# LANGUAGE RecordWildCards #-}

this will implicitly write for every parameter foo, foo=foo if you write {..} when we do record pattern matching.

这将隐式地写入每个参数foo, foo=foo。当我们做记录模式匹配时。

So we can then write:

所以我们可以这样写:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {..}) = foo
someOtherFunction (Qux {..}) = foo + qux

So here the compiler implicitly pattern matched all parameters with a variable with the same name, such that we can access those parameters without explicit pattern matching, nor by using getters.

因此,在这里,编译器隐式模式与具有相同名称的变量匹配所有参数,这样我们就可以在没有显式模式匹配的情况下访问这些参数,也不能使用getter来访问这些参数。

The advantage is thus that we save a lot on large code chunks that have to be written manually. A downside is however the fact that the parameters are no longer explicitly and hence the code is harder to understand. We see the use of parameters for which there exist actually getter counterparts, and thus it can introduce some confusion.

这样做的好处是我们可以在需要手工编写的大型代码块上节省很多。但是,缺点是参数不再显式,因此代码更难理解。我们看到了一些参数的使用,这些参数实际上是有getter对应的,因此它可以引入一些混淆。

Like @leftroundabout says, probably lenses can do the trick as well, and it will prevent introducing variables that basically shadow getters, etc.

就像@leftroundabout说的那样,也许镜头也能做到这一点,它会阻止引入基本阴影的变量等等。

You can also merge the RecordWildCards with pattern matching on parameters, for example:

您还可以将记录通配符合并到参数的模式匹配上,例如:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {bar=[], ..}) = foo
someOtherFunction (Bar {..}) = foo + 42
someOtherFunction (Qux {..}) = foo + qux

So here in case the bar parameter of a Foo instance with a Bar data constructor is the empty string, we return the foo value, otherwise we add 42 to it.

这里,如果一个Foo实例的bar参数和一个bar数据构造函数是空字符串,我们返回Foo值,否则我们会在它上面加上42。

#2


4  

It's the RecordWildCards syntax extension. From the docs:

它是RecordWildCards语法扩展。从文档:

For records with many fields, it can be tiresome to write out each field individually in a record pattern ... Record wildcard syntax permits a ".." in a record pattern, where each elided field f is replaced by the pattern f = f ... The expansion is purely syntactic, so the record wildcard expression refers to the nearest enclosing variables that are spelled the same as the omitted field names.

对于有许多字段的记录,用记录模式单独写出每个字段是很烦人的……在记录模式中,记录通配符语法允许“..”,在记录模式中,每个被省略的字段f被替换为f = f的模式。扩展是纯语法的,所以记录通配符表达式是指最近的封闭变量,这些变量的拼写与被省略的字段名相同。

Basically it brings the fields of a record into scope.

基本上它将记录的字段引入范围。

It is particularly useful when writing encoders/decoders (e.g. Aeson), but should be used sparingly in the interest of code clarity.

它在编写编码器/译码器(如Aeson)时特别有用,但应该谨慎使用,以使代码清晰。

#1


15  

In short: it is an extension of GHC called RecordWildCards.

简而言之:它是GHC的一个扩展,称为RecordWildCards。

In Haskell you can use record syntax to define data types. For example:

在Haskell中,您可以使用记录语法来定义数据类型。例如:

data Foo = Bar { foo :: Int, bar :: String } | Qux { foo :: Int, qux :: Int }

We can then pattern match on the data constructor, and match zero or more parameters, for example:

然后,我们可以对数据构造函数进行模式匹配,并匹配零个或多个参数,例如:

someFunction :: Int -> Foo -> Foo
someFunction dd (Bar {foo=x}) = dd + x
someFunction dd (Qux {foo=x, qux=y}) = dd + x + y

But it can happen that we need access to a large amount (or even all) parameters. Like for example:

但是,我们需要访问大量(甚至所有)参数。例如:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {foo=foo, bar=bar}) = foo
someOtherFunction (Qux {foo=foo, qux=qux}) = foo + qux

In case the number of parameters is rather large, then this becomes cumbersome. There is an extension RecordWildCards:

如果参数的数量相当大,那么这将变得很麻烦。有一个扩展记录通配符:

{-# LANGUAGE RecordWildCards #-}

this will implicitly write for every parameter foo, foo=foo if you write {..} when we do record pattern matching.

这将隐式地写入每个参数foo, foo=foo。当我们做记录模式匹配时。

So we can then write:

所以我们可以这样写:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {..}) = foo
someOtherFunction (Qux {..}) = foo + qux

So here the compiler implicitly pattern matched all parameters with a variable with the same name, such that we can access those parameters without explicit pattern matching, nor by using getters.

因此,在这里,编译器隐式模式与具有相同名称的变量匹配所有参数,这样我们就可以在没有显式模式匹配的情况下访问这些参数,也不能使用getter来访问这些参数。

The advantage is thus that we save a lot on large code chunks that have to be written manually. A downside is however the fact that the parameters are no longer explicitly and hence the code is harder to understand. We see the use of parameters for which there exist actually getter counterparts, and thus it can introduce some confusion.

这样做的好处是我们可以在需要手工编写的大型代码块上节省很多。但是,缺点是参数不再显式,因此代码更难理解。我们看到了一些参数的使用,这些参数实际上是有getter对应的,因此它可以引入一些混淆。

Like @leftroundabout says, probably lenses can do the trick as well, and it will prevent introducing variables that basically shadow getters, etc.

就像@leftroundabout说的那样,也许镜头也能做到这一点,它会阻止引入基本阴影的变量等等。

You can also merge the RecordWildCards with pattern matching on parameters, for example:

您还可以将记录通配符合并到参数的模式匹配上,例如:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {bar=[], ..}) = foo
someOtherFunction (Bar {..}) = foo + 42
someOtherFunction (Qux {..}) = foo + qux

So here in case the bar parameter of a Foo instance with a Bar data constructor is the empty string, we return the foo value, otherwise we add 42 to it.

这里,如果一个Foo实例的bar参数和一个bar数据构造函数是空字符串,我们返回Foo值,否则我们会在它上面加上42。

#2


4  

It's the RecordWildCards syntax extension. From the docs:

它是RecordWildCards语法扩展。从文档:

For records with many fields, it can be tiresome to write out each field individually in a record pattern ... Record wildcard syntax permits a ".." in a record pattern, where each elided field f is replaced by the pattern f = f ... The expansion is purely syntactic, so the record wildcard expression refers to the nearest enclosing variables that are spelled the same as the omitted field names.

对于有许多字段的记录,用记录模式单独写出每个字段是很烦人的……在记录模式中,记录通配符语法允许“..”,在记录模式中,每个被省略的字段f被替换为f = f的模式。扩展是纯语法的,所以记录通配符表达式是指最近的封闭变量,这些变量的拼写与被省略的字段名相同。

Basically it brings the fields of a record into scope.

基本上它将记录的字段引入范围。

It is particularly useful when writing encoders/decoders (e.g. Aeson), but should be used sparingly in the interest of code clarity.

它在编写编码器/译码器(如Aeson)时特别有用,但应该谨慎使用,以使代码清晰。