Haskell 列出部分应用的功能(优雅或惯用)

Haskell 列出部分应用的功能(优雅或惯用),haskell,currying,Haskell,Currying,我几乎可以在哈斯克尔的问题中蹒跚前行,但我还没有找到更好的解决办法 假设我有一个函数f,它有5个参数,我想创建一个部分应用函数的列表,这些函数应用了前3个参数,但列表中的每个元素都不同 例如,假设f::numa=>a->a->a->a->b->b->c,我想以[b->b->c]作为结果的类型。其中一个函数可能是F135,另一个函数可能是F642 只要有一个论点,我就可以 map f [1..4] 要获取f1,f2,我可以使用2个参数 map (uncurry f) $ zip [1..3]

我几乎可以在哈斯克尔的问题中蹒跚前行,但我还没有找到更好的解决办法

假设我有一个函数
f
,它有5个参数,我想创建一个部分应用函数的列表,这些函数应用了前3个参数,但列表中的每个元素都不同

例如,假设
f::numa=>a->a->a->a->b->b->c
,我想以
[b->b->c]
作为结果的类型。其中一个函数可能是
F135
,另一个函数可能是
F642

只要有一个论点,我就可以

map f [1..4] 
要获取
f1
f2
,我可以使用2个参数

map (uncurry f) $ zip [1..3] [6..8].
现在我可以做3个参数了

map (uncurry $ uncurry f) $ zip (zip [1..3] [6..8]) [3..5]
但这变得非常丑陋,非常快。有没有更优雅(或惯用)的方法来实现这一点(除了让我自己的“uncurry3”函数与
zip3
配对之外)?我总是在Haskell那里遇到一个优雅的解决方案,这看起来非常笨拙


抱歉,如果这是一个新手问题或之前已经回答过。谢谢。

您可以使用
zipWith
缩短双参数代码:

zipWith f [1..3] [6..8]
方便的是,在标准库中实际上定义了一个(以此类推,最多7个)

还有
-XParallelListComp
,它似乎可以增加到任何数字:

[f a b c | a <- [1..3] | b <- [6..8] | c <- [3..5]]

[f a b c | a这实际上是为列表定义应用程序实例的一种方法

回想一下,Applicative的定义是围绕
()
的定义展开的:

也许这开始看起来像是一种可以实现这一点的方法?你有一个函数列表,你可以将它们应用到一个值列表中。也许我们可以让
()
以某种方式工作,以便它将函数列表应用到值列表中,如zip:

fs <*> xs = zipWith ($) fs xs
因此,
zipWith
“zips”函数列表和值列表,并返回将每个函数应用于相应值的结果

我想你应该可以从这里开始。让我们把两个列表加在一起:

(fmap (+) [1,2,3]) <*> [4,5,6]

三参数函数怎么样

f x y z = x * y + z

((fmap f [1,2,3]) <*> [4,5,6]) <*> [7,8,9]
([(\y z -> 1*y+z), (\y z > 2*y+z), (\y z -> 3*y+z)] <*> [4,5,6]) <*> [7,8,9]
[(4+), (10+), (18+)] <*> [7,8,9]
[11, 18, 27]
这很简单,对吧?现在你基本上可以做一个
zipWithN
zipWith
,有你想要的参数

不幸的是,
[]的默认应用程序实例
没有这种行为;它的行为方式与其Monad实例一致。因此,为了避免这种情况,我们通常使用一个新类型包装器,让我们为同一类型定义不同的实例。在标准库中,在
控件.Applicative
中,新类型包装器是
ZipList

data ZipList a = ZipList { getZipList :: [a] }

instance Applicative ZipList where
    (ZipList fs) <*> (ZipList xs) = ZipList (zipWith ($) fs xs)
    pure x                        = -- left as exercise, it might surprise you :)
但“优势”在于,你基本上可以任意固定“提升”:


这里真正需要注意的是,这正是“这种模式”这个应用程序是为了解决问题而发明的;这是一个非常常见的模式/领域,应用程序尤其在其中蓬勃发展。开始建立一种直觉,以便能够发现问题的迹象,这可能是一个很好的应用程序解决方案。

zipWith应该对我来说很好,我没有一个令人讨厌的数字rgs,但感谢平行列表比较的指导。感谢教程!我回忆起以前的一些讨论,这个版本的
()
列表应该作为一个函数包含在基本库中,但遗憾的是,这并没有发生。但是它作为
zap
存在于Edward Kmett的
keys
包中。
(fmap (+) [1,2,3]) <*> [4,5,6]
[(1+), (2+), (3+)] <*> [4,5,6]
[1+4, 2+5, 3+6]
[5, 7, 9]
f x y z = x * y + z

((fmap f [1,2,3]) <*> [4,5,6]) <*> [7,8,9]
([(\y z -> 1*y+z), (\y z > 2*y+z), (\y z -> 3*y+z)] <*> [4,5,6]) <*> [7,8,9]
[(4+), (10+), (18+)] <*> [7,8,9]
[11, 18, 27]
f <$> [1,2,3] <*> [4,5,6] <*> [7,8,9]
data ZipList a = ZipList { getZipList :: [a] }

instance Applicative ZipList where
    (ZipList fs) <*> (ZipList xs) = ZipList (zipWith ($) fs xs)
    pure x                        = -- left as exercise, it might surprise you :)
f <$> ZipList [1,2,3] <*> ZipList [4,5,6] <*> ZipList [7,8,9]
zipWith3 f [1,2,3] [4,5,6] [7,8,9]