Haskell 是否有指向记录成员的指针/引用?
我可以使用 ::*
、.*
和 ->*
语法创建和引用 C++ 中结构成员的相对指针,例如:
char* fstab_t::*field = &fstab_t::fs_vfstype;
my_fstab.*field = ...
在Haskell中,我可以轻松地为记录获取器创建临时标签,例如:
(idxF_s,idxL_s) = swap_by_sign sgn (idxF,idxL) ;
Afaik,但是我无法使用这些获取器作为标签来更新记录,例如:
a { idxF_s = idxL_s b }
是否有一种简单的方法可以做到这一点,而无需为每个记录设置器进行编码?
I can create and reference relative pointers to struct members in C++ using the ::*
, .*
, and ->*
syntax like :
char* fstab_t::*field = &fstab_t::fs_vfstype;
my_fstab.*field = ...
In Haskell, I can easily create temporary labels for record getters like :
(idxF_s,idxL_s) = swap_by_sign sgn (idxF,idxL) ;
Afaik, I cannot however then update records using these getters as labels like :
a { idxF_s = idxL_s b }
Is there an easy way to do this without coding for each record setter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
捆绑在一起的一等值中的 getter 和 setter 称为透镜。有很多包可以做到这一点;最流行的是 data-lens 和 fclabels。这个上一个问题是很好的介绍。
这两个库都支持使用 Template Haskell 从记录定义中派生镜头(使用 data-lens,它以 一个额外的包以实现可移植性)。您的示例将表示为(使用数据镜头语法):(
或等效:
idxF_s ^= (b ^.idL_s) $ a
)当然,您可以通过通用方式转换镜头将它们的 getter 和 setter 一起转换:(
或者等效地:
negateLens l = iso negate negate .l
1)一般来说,我建议您在任何时候都使用镜头必须处理任何类型的重要记录处理;它们不仅极大地简化了记录的纯粹转换,而且两个包都包含使用镜头访问和修改状态单子状态的便利函数,这非常有用。 (对于 data-lens,您需要使用 data-lens-fd 包以在任何
MonadState
中使用这些便利函数;同样,为了可移植性,它们位于单独的包中。)1 当使用任一包时,您应该启动您的模块与:
这是因为他们使用 Prelude 的
id
和(.)
函数的通用形式 -id
可以用作从任何值到自身的镜头(并非所有值)无可否认,这很有用),并且(.)
用于组成镜头(例如getL (fieldA . fieldB) a
与getL fieldA . getL fieldB 相同$a
)。较短的negateLens
定义使用了它。A getter and setter bundled together in a first-class value is referred to as a lens. There are quite a few packages for doing this; the most popular are data-lens and fclabels. This previous SO question is a good introduction.
Both of those libraries support deriving lenses from record definitions using Template Haskell (with data-lens, it's provided as an additional package for portability). Your example would be expressed as (using data-lens syntax):
(or equivalently:
idxF_s ^= (b ^. idL_s) $ a
)You can, of course, transform lenses in a generic way by transforming their getter and setter together:
(or equivalently:
negateLens l = iso negate negate . l
1)In general, I would recommend using lenses whenever you have to deal with any kind of non-trivial record handling; not only do they vastly simplify pure transformation of records, but both packages contain convenience functions for accessing and modifying a state monad's state using lenses, which is incredibly useful. (For data-lens, you'll want to use the data-lens-fd package to use these convenience functions in any
MonadState
; again, they're in a separate package for portability.)1 When using either package, you should start your modules with:
This is because they use generalised forms of the Prelude's
id
and(.)
functions —id
can be used as the lens from any value to itself (not all that useful, admittedly), and(.)
is used to compose lenses (e.g.getL (fieldA . fieldB) a
is the same asgetL fieldA . getL fieldB $ a
). The shorternegateLens
definition uses this.这里你想要的是一流的记录标签,虽然这在语言中不存在,但 Hackage 上有几个包实现了这种模式。其中之一是 fclabels,它可以使用 Template Haskell 为您生成所需的样板。这是一个例子:
What you want here is first-class record labels, and while this does not exist in the language, there are several packages on Hackage which implement this pattern. One of these is fclabels, which can use Template Haskell to generate the required boilerplate for you. Here's an example: