如何在haskell中读取`Typ {..}`的语法?

Wor*_*der 10 syntax haskell

这里阅读库代码时,我注意到一个看起来非常奇怪的语法,我无法理解:

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
Run Code Online (Sandbox Code Playgroud)

相关的定义System包括一个记录{ _sysJacobian :: R n -> L m n },并且{ cfgVelocities :: R n }是记录声明的一部分Config所以我相信我知道代码的作用,我认为代码是相当可读的,是作者的道具.

问题是:这个语法叫什么,我怎么能用它?

Wil*_*sem 15

简而言之:它是GHC被叫的延伸RecordWildCards.

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

data Foo = Bar { foo :: Int, bar :: String } | Qux { foo :: Int, qux :: Int }
Run Code Online (Sandbox Code Playgroud)

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

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

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

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {foo=foo, bar=bar}) = foo
someOtherFunction (Qux {foo=foo, qux=qux}) = foo + qux
Run Code Online (Sandbox Code Playgroud)

如果参数的数量相当大,则这变得麻烦.有一个扩展RecordWildCards:

{-# LANGUAGE RecordWildCards #-}
Run Code Online (Sandbox Code Playgroud)

这将隐写的每一个参数foo,foo=foo如果你写{..}的时候,我们做记录图形匹配.

那么我们可以写:

someOtherFunction :: Foo -> Int
someOtherFunction (Bar {..}) = foo
someOtherFunction (Qux {..}) = foo + qux
Run Code Online (Sandbox Code Playgroud)

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

因此,优点是我们可以节省大量必须手动编写的大代码块.然而,缺点是参数不再明确,因此代码难以理解.我们看到实际存在吸气剂的参数的使用,因此它可能引入一些混淆.

就像@leftroundabout所说,可能镜头也可以做到这一点,并且它会阻止引入基本上影响吸气剂的变量等.

您还可以合并RecordWildCards参数上的模式匹配,例如:

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

所以如果带有数据构造函数barFoo实例的参数Bar是空字符串,我们返回foo值,否则我们添加42它.