haskell - 如何阅读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
所以我相信我知道代码的作用,我认为代码的可读性很强,对作者的支持。
问题是:这种语法叫什么,我该如何使用它?
解决方案
简而言之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
的实例的参数是空字符串,我们返回值,否则我们添加它。Foo
Bar
foo
42
推荐阅读
- dependency-injection - 如何在 .NET Core 中创建同一个单例服务的多个实例?
- subdomain - 由于来自 Fritzbox 的域错误,服务器拒绝请求
- javascript - 为什么我的倒计时功能不起作用?
- sql - 使用嵌套集模型同时删除多条记录
- java - 如何将我的流值映射到我的对象类
- kubernetes - 警告日志 metricbeat pod(在 kubernetes 上):DNS 查找失败“k8s-node4”:在 10.96.0.10:53 上查找 k8s-node4:没有这样的主机
- javascript - 如果对象数组中的id匹配,如何插入名称值
- c# - 仅适用于当前连接/用户的静态类/值
- mysql - SQL 数据库转储/文本解析
- javascript - 将 JSX 内容移动到单独的文件时,它无法正确呈现