gpt4 book ai didi

haskell - 将函数映射到代数数据类型的字段的更简洁的方法?

转载 作者:行者123 更新时间:2023-12-03 20:27:48 25 4
gpt4 key购买 nike

我有一个包含很多字段的数据类型:

data ManyFields a b c d .. = MF { f1 :: a, f2 :: b, f3 :: c .. }

问题一

如何在避免实现 map 的同时将函数映射到每个字段每个功能。
例如,这看起来非常乏味且不习惯:
-- | Note I am explicitly constructing ManyField after mapping a function onto the field
-- | This looks bad
mapf1 :: (a -> a1) -> ManyFields a b c .. -> ManyFields a1 b c ..
mapf1 g mf = MF (g . f1 $ mf) (f2 mf) ..

-- | Repeat for each field
mapf2 :: (b -> b1) -> ManyFields a b c .. -> ManyFields a b1 c ...

我认为某种高阶函数可以抽象出 constructor . (mapfunction f) 的模式会减少样板,但有更好的解决方案吗?

问题二

如果我想将许多 ManyFields 压缩在一起并将任意数量的函数映射到每个字段上,这听起来像是某种类型类的实例吗?

用例:
(==) `mapFunction` mf1 `pairWiseZipField` mf2 

它对我来说有点像一个应用程序,但我再次不确定如何实现 fmap到这种类型。

最佳答案

您无法使用标准功能真正做到这一点。最好的方法是为每个字段设置一个 map 功能。令人高兴的是,您可以使用 lens 中的一些模板 haskell 自动生成这些。图书馆。它看起来像这样:

data ManyFields a b c d = MF { _f1 :: a, _f2 :: b, _f3 :: c, _f4 :: d }

makeLenses ''ManyFields

这将为 ManyFields 的每个字段生成一个镜头.镜头是一个简单的构造,允许您访问和更改那里的值——更改甚至可以是多态的,就像 map 一样!请注意每个字段如何以下划线为前缀:镜头与字段名称相同减去下划线。

您现在可以像这样访问值:
> foo = MF 'a' "b" 3 False
> foo^.f1
'a'

您可以使用 set 设置值运算符(operator)。当与镜头一起使用时,它会创建一个 setter 函数:
> :t set f1
set f1 :: a' -> ManyFields a b c d -> ManyFields a' b c d

要实际使用它,您可以这样做:
> set f1 () foo
MF () "b" 3 False

由于您有一个 getter 和一个 setter,因此编写一个 map 函数非常简单。幸运的是,我们甚至不必这样做:库提供了一个名为 over 的函数。 :
> :t over f1 
over f1 :: (a -> a') -> ManyFields a b c d -> ManyFields a' b c d

如果你更喜欢中缀运算符, set也可调用 .~及以上可调用 %~ . (后者有一个助记符: % 是 mod,或“修改”:P。)这对 & 也很有用。只是 $ 的运算符翻转。所以以下两个版本是相等的:
> over f1 ord foo
MF 97 "b" 3 False
> foo & f1 %~ ord
MF 97 "b" 3 False

个人觉得运营商有点多。除非你要到处使用镜头,否则我会坚持 setover .

我不知道您描述的压缩功能的好解决方案。但是一定要看看镜头库的其余部分——它非常大,你永远不知道你会找到什么!

关于haskell - 将函数映射到代数数据类型的字段的更简洁的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16974868/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com