避免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)