避免haskell中的长元组定义

避免haskell中的长元组定义,haskell,tuples,hxt,Haskell,Tuples,Hxt,对于我与的工作,我实现了以下功能: -- | Construction of a 8 argument arrow from a 8-ary function. Same -- implementation as in @Control.Arrow.ArrowList.arr4@. arr8 :: ArrowList a => (b1 -> b2 -> b3 -> b4 -> b5 -> b6 -> b7 -> b8 -> c)

对于我与的工作,我实现了以下功能:

-- | Construction of a 8 argument arrow from a 8-ary function. Same
-- implementation as in @Control.Arrow.ArrowList.arr4@.
arr8 :: ArrowList a => (b1 -> b2 -> b3 -> b4 -> b5 -> b6 -> b7 -> b8 -> c)
                -> a (b1, (b2, (b3, (b4, (b5, (b6, (b7, b8))))))) c
arr8 f = arr ( \ ~(x1, ~(x2, ~(x3, ~(x4, ~(x5, ~(x6, ~(x7, x8)))))))
               -> f x1 x2 x3 x4 x5 x6 x7 x8 )
如haddock注释中所述,上述函数
arr8
接受一个8元函数并返回一个8参数箭头。我使用这样的函数:
(x1&&x2&&&x8)>>arr8f
,其中
x1
x8
是箭头

我的问题:有没有办法避免大元组定义?是否有更优雅的
arr8
实现


信息:我使用了与函数中相同的代码模式(请参见)

我的方法是编写

arr8 f = arr (uncurry8 f)
我不知道我们是否可以编写一个通用的
uncurryN n f
函数(可能不会),但我可以为每个
n
系统地提供一个无点
uncurryN

uncurry3 f = uncurry ($) . cross (uncurry . f) id
uncurry4 f = uncurry ($) . cross (uncurry3 . f) id
...
uncurry8 f = uncurry ($) . cross (uncurry7 . f) id
在哪里


这是可行的,尽管它依赖于一些相当深刻和脆弱的类型类魔法。它还要求我们将元组结构更改为更规则一点。特别是,它应该是一个类型级别的链表,更喜欢
(a,(b,(c,())
,而不是
(a,(b,c))

现在我们可以做了

> zup (+) (1, (2, ()))
3

> :t arrTup (+)
arrTup (+)
  :: (Num a1, Arrow a, Zup b n, Fun n b c ~ (a1 -> a1 -> a1)) =>
     a b c

> arrTup (+) (1, (2, ()))
3
如果要定义特定的变量,它们都是
arrTup

arr8 
  :: Arrow arr 
  => (a -> b -> c -> d -> e -> f -> g -> h -> r)
  -> arr (a, (b, (c, (d, (e, (f, (g, (h, ())))))))) r
arr8 = arrTup

最后值得注意的是,如果我们定义一个懒惰的
uncurry

uncurryL :: (a -> b -> c) -> (a, b) -> c
uncurryL f ~(a, b) = f a b
然后我们可以用一种说明这里发生了什么的方式来编写
Zup
的递归分支

instance Zup b => Zup (a, b) where 
  zup f = uncurryL (zup . f)

我必须查找
~
的用法,所以这里有一个其他人的链接:是的!这里的核心技术并不重要,只是模仿了@tampis的要求。请注意,我在其中一条评论中使用了
(~)
,原因不同,
(a~b)
的意思是“
a
b
的类型相同”。我在更早更复杂的版本中使用了它,直到我注意到我已经停止使用它:)@J.Abrahamson:谢谢你优雅的解决方案!;-)@J.Abrahamson:你知道hackage软件包已经提供了你的解决方案吗?请注意,
cross
通常是书面的(而
pair
是书面的)。
uncurryL :: (a -> b -> c) -> (a, b) -> c
uncurryL f ~(a, b) = f a b
instance Zup b => Zup (a, b) where 
  zup f = uncurryL (zup . f)