首页 > 解决方案 > 如何阅读haskell中的语法`Typ{..}`?

问题描述

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

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

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

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

标签: haskellsyntax

解决方案


简而言之GHC:它是被调用的扩展RecordWildCards

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

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

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

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

但是可能会发生我们需要访问大量(甚至全部)参数的情况。例如:

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

如果参数的数量相当大,那么这变得很麻烦。有一个扩展RecordWildCards

{-# LANGUAGE RecordWildCards #-}

如果您在我们记录模式匹配时写入foo,这将隐式写入每个参数。foo=foo{..}

所以我们可以这样写:

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

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

因此,优点是我们节省了大量必须手动编写的大代码块。然而,缺点是参数不再显式,因此代码更难理解。我们看到实际存在 getter 对应物的参数的使用,因此它可能会引入一些混淆。

就像@leftroundabout 说的那样,镜头可能也可以做到这一点,并且它可以防止引入基本上阴影吸气剂等的变量。

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

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

所以这里如果带有数据构造函数bar的实例的参数是空字符串,我们返回值,否则我们添加它。FooBarfoo42


推荐阅读