在这里阅读库代码时,我注意到一个看起来非常奇怪的语法,我无法理解:
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)
所以如果带有数据构造函数bar的Foo实例的参数Bar是空字符串,我们返回foo值,否则我们添加42它.