Haskell函数什么时候应该接受元组,而不是多个参数?

Haskell函数什么时候应该接受元组,而不是多个参数?,haskell,tuples,typeclass,multimethod,Haskell,Tuples,Typeclass,Multimethod,在typeclass方法中,collide被定义为将一个2元组作为其单个参数,而不是两个“正常”参数(我想我理解部分应用程序等) 这样做的目的是什么 什么时候使用元组参数比使用多个参数更好?我几乎从不编写将元组作为参数的函数。如果出现变量内在连接的情况(正如Bheklillr在一篇评论中提到的),我更可能将其放入它自己的单独数据类型和模式匹配中 一种常见的情况是,您可能希望定义一个以元组为参数的函数,即您有一个动态生成的元组列表(或任意的Functor),但希望使用某个函数映射它,例如 grid

在typeclass方法中,
collide
被定义为将一个2元组作为其单个参数,而不是两个“正常”参数(我想我理解部分应用程序等)

这样做的目的是什么


什么时候使用元组参数比使用多个参数更好?

我几乎从不编写将元组作为参数的函数。如果出现变量内在连接的情况(正如Bheklillr在一篇评论中提到的),我更可能将其放入它自己的单独数据类型和模式匹配中

一种常见的情况是,您可能希望定义一个以元组为参数的函数,即您有一个动态生成的元组列表(或任意的
Functor
),但希望使用某个函数映射它,例如

grid :: [(Int, Int)]
grid = (,) <$> [1..10] <*> [1..10]
在这种情况下,我更愿意使用
uncurry
:(a->b->c)->(a,b)->c
)像正常情况一样使用
+

sumPoints :: [(Int, Int)] -> [Int]
sumPoints = map (uncurry (+))
这可以说是更清晰、更简短;定义高阶类似物也非常容易,例如
uncurry3
,例如:

> let uncurry3 f (a, b, c) = f a b c
> uncurry3 (\a b c -> a + b + c) (1, 2, 3)
6

我会说,通常情况下,函数应该是curried(所以没有元组),除非参数本身是元组。例如,如果您编写一个函数来添加两个数字,那么您有两个参数,因此您应该编写它:

add :: Num a => a -> a -> a
add x y = x + y
现在,如果出于某种原因,您使用2-uple作为二维点,并且您希望添加两个点。直到有两个参数,看起来是元组,所以你可以这样写

add :: Num a => (a,a) -> (a,a) -> (a,a)
add (x,y) (x,y') = (x+x', y+y')
书写

add :: Num a => a -> a -> a -> a -> (a,a)
add a b c d = (a+c, b+d)
因为您处理的实体是元组,所以没有意义。 你也不会那样写

add :: Num a => ((a,a),(a,a)) -> (a,a)

在我们的示例中,当要检查的内容作为元组提供时,可能总是在上下文中调用
collide
函数(因为可能有一个阶段收集所有可能的冲突,从而生成一个2元组列表)。在这种情况下,使用无载波函数可能更容易,因此您可以在其上映射
collide

您可能希望了解这一点:我的观点是,当两个值本质上是连接的时,应该使用元组,例如表示坐标的元组
(x,y)
。幸运的是,对于2元组,我们有
curry
uncurry
可以在这些表示形式之间进行转换,以便在一种表示形式比另一种表示形式更方便的情况下进行转换。元组的另一个重要用途是当您不想创建自定义数据类型,但仍然希望使用同义词来保持类型签名清晰时:
type FName=String;类型LName=字符串;类型年龄=整数;类型Person=(FName,LName,Age);问候::Person->IO();greet(fname,lname,age)=putStrLn$如果age>=30,则“Hello,”++fname++“+++lname else”Sup?
@chrisdew这取决于问题的类型。正如bhekilir所建议的,如果值是连接的,则使用元组。大多数时候我不使用元组。我将元组结构制作成一个记录,如果它们是内在连接的。Currying允许更容易的重用,所以我通常会坚持使用它。@chrisdw在您的示例中,我个人会选择将参数分离为
collide
,因为您不太可能与同一对象发生多次碰撞,例如
数据流星=流星;实例碰撞行星流星…
流星雨::[Meteor]->[String];流星雨=地图(翻转碰撞行星)
,而如果使用元组,则必须编写它
流星雨=地图(\m->collide(m,Planet)
。虽然字符数大致相同,但我个人认为前者更具可读性。
add :: Num a => a -> a -> a -> a -> (a,a)
add a b c d = (a+c, b+d)
add :: Num a => ((a,a),(a,a)) -> (a,a)