【发布时间】:2015-03-30 20:08:40
【问题描述】:
我正在尝试将函数元组应用于值元组
λ> let foo = ((+1), (*3), ((:)5)) #Each function has type: a -> a
λ> let bar = (1, 5, [0]) #Each value of the corresponding tuple has type a
如何实现:
toImplement foo bar = ?
这样:
λ> toImplement foo bar
-> (2, 15, [0,5]) # using foo and bar above
对于任何有效的 foo 和 bar(长度相同),您一般如何实现这一点?
[我看了this problem,但它是为固定类型实现的。我需要一个通用的实现]
动机:
我正在尝试有效地编写折叠。
let acc1 = \x acc -> x*x:acc
let acc2 = (+)
foldr (\x acc -> (acc1 x (fst acc), acc2 x ( snd acc))) ([],0) [1..10]
> ([1,4,9,16,25,36,49,64,81,100],55)
我有 2 个不同的累加器 acc1 和 acc2 只在列表中循环一次。我想对任意数量的累加器执行此操作,所有这些累加器的类型均为 a -> b [其中 a 是列表中元素的类型,b 是累加器输出的类型] 它看起来很笨拙,必须使用 fst 和 snd 访问元组:/
【问题讨论】:
-
"一般来说,你如何为任何有效的 foo 和 bar(相同长度)实现这一点?" --- 你不能使它对元组通用。
-
你不能写一个
toImplement来处理任意大小的元组。当然,可能有一些非常骇人听闻的方法可以使用高级语言功能和一堆扩展来让它工作,但它可能比复制/粘贴基本相同的定义多次以获得toImplement、@987654328 更麻烦@ ..toImplementN. -
Haskell 不允许使用任意元组的背后有什么禅意吗?
-
这行不通不是因为 Haskell 列表要求列表的所有元素都相同,并且列表可以是任意长度(不赞成无穷大),但 Haskell 元组允许任何类型要在其中,但它们必须是固定大小。所以你的问题基本上是在这两个限制之间寻找一个甜蜜点,但实际上不可能找到一个。 Python 可以让你这样做,但 Haskell 不行
-
对于您的折叠用例,您可以通过使用 lambda 中的模式匹配解构元组来使其更好一点:
(\x (a, b) -> ...)。对于更短的解决方案,您可以使用来自Control.Arrow的(***):foldr (\x -> acc1 x *** acc2 x) ([],0) [1..10]。您甚至可以使用Applicative消除所有 lambda(尽管我建议使用其他更简单的基于(***)的解决方案):foldr ((***) <$> acc1 <*> acc2) ([],0) [1..10]。
标签: haskell