gpt4 book ai didi

haskell - "zipping"相同长度的元组是否有 Haskell 镜头功能?

转载 作者:行者123 更新时间:2023-12-04 11:18:50 24 4
gpt4 key购买 nike

我希望能够使用一个函数组合两个相同长度的元组,类似于 zipWith函数来自 base .
例如,对于长度为 3 个元组的情况:

zipTupleWith f (a0,a1,a2) (b0,b1,b2) = (f a0 b0, f a1 b1, f a2 b2)
虽然我想要一个适用于任何长度的单一功能。
我做了一个函数 zipTupleWith使用 lens包裹:
zipTupleWith :: (Each s1 t1 a a, Each s2 s2 b b) => (a -> b -> a) -> s1 -> s2 -> t1
zipTupleWith f a b = a & partsOf each %~ flip (zipWith f) (b ^.. each)
这个可以 zipWith两个元组,只要函数是 a -> b -> a 类型.这个限制是因为 partsOf用于参数 a 的函数.
我对我的解决方案不满意的原因有 3 个:
  • 我希望能够使用 a -> b -> c 类型的函数, 允许 zipTuple = zipTupleWith (,) 之类的东西.
  • 上述实现不会捕获由传入的不同长度的元组引起的错误(zipTupleWith (+) (1,2,3) (100,100) = (101, 102, 3) - 我希望这是一个编译错误)。
  • 它创建一个中间列表( b ^.. each )。

  • 那么,有没有办法使用光学来做到这一点?
    我看到 tuple-th package 可以做到这一点,但我宁愿避免为此添加另一个依赖项,而 Template Haskell 似乎对我正在做的事情来说太过分了。

    最佳答案

    我知道您要求使用基于镜头的方法,但如果您只有小元组,您可以使用类型类实现您想要的,而不会有太多麻烦。例如考虑:

    class ZipTuple as a where
    type TupOf as x :: *
    zipTuple :: (a -> b -> c) -> as -> TupOf as b -> TupOf as c

    instance ZipTuple (a,a) a where
    type TupOf (a,a) b = (b,b)
    zipTuple f (a1,a2) (b1,b2) = (f a1 b1, f a2 b2)

    instance ZipTuple (a,a,a) a where
    type TupOf (a,a,a) b = (b,b,b)
    zipTuple f (a1,a2,a3) (b1,b2,b3) = (f a1 b1, f a2 b2, f a3 b3)
    可能有一种更优雅的方式来编写它,但模式很简单。为您想要的任何长度的元组添加实例应该很容易。

    如果你想要任意长的元组但不想要模板 haskell,还有泛型路线。这是一个基于通用表示的形状压缩的解决方案:
    import GHC.Generics

    class TupleZipG fa fb a b c | fa -> a, fb -> b where
    type Out fa fb a b c :: (* -> *)
    tupleZipG :: (a -> b -> c) -> fa x -> fb x -> Out fa fb a b c x

    instance (TupleZipG l1 l2 a b c, TupleZipG r1 r2 a b c) => TupleZipG (l1 :*: r1) (l2 :*: r2) a b c where
    type Out (l1 :*: r1) (l2 :*: r2) a b c = Out l1 l2 a b c :*: Out r1 r2 a b c
    tupleZipG f (l1 :*: r1) (l2 :*: r2) = tupleZipG f l1 l2 :*: tupleZipG f r1 r2

    instance TupleZipG (S1 m (Rec0 a)) (S1 m' (Rec0 b)) a b c where
    type Out (S1 m (Rec0 a)) (S1 m' (Rec0 b)) a b c = S1 m (Rec0 c)
    tupleZipG f (M1 (K1 a)) (M1 (K1 b)) = M1 $ K1 $ f a b

    instance TupleZipG fa fb a b c => TupleZipG (D1 m fa) (D1 m' fb) a b c where
    type Out (D1 m fa) (D1 m' fb) a b c = D1 m (Out fa fb a b c)
    tupleZipG f (M1 a) (M1 b) = M1 $ tupleZipG f a b

    instance TupleZipG fa fb a b c => TupleZipG (C1 m fa) (C1 m' fb) a b c where
    type Out (C1 m fa) (C1 m' fb) a b c = C1 m (Out fa fb a b c)
    tupleZipG f (M1 a) (M1 b) = M1 $ tupleZipG f a b

    tupleZip
    :: (TupleZipG (Rep as) (Rep bs) a b c, Generic cs, Generic as,
    Generic bs, Out (Rep as) (Rep bs) a b c ~ Rep cs) =>
    (a -> b -> c) -> as -> bs -> cs
    tupleZip f t1 t2 = to $ tupleZipG f (from t1) (from t2)
    警告:类型推断不适用于这种通用方法。

    关于haskell - "zipping"相同长度的元组是否有 Haskell 镜头功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67796714/

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