7

http://www.haskell.org/pipermail/haskell-cafe/2007-August/030096.html中,typeclass 方法collide被定义为将 2 元组作为其单个参数,而不是两个“正常”参数(我认为我了解部分应用等)。

{-# OPTIONS_GHC -fglasgow-exts
        -fallow-undecidable-instances
        -fallow-overlapping-instances #-}

module Collide where

class Collide a b where
    collide :: (a,b) -> String

data Solid = Solid
data Asteroid = Asteroid
data Planet = Planet
data Jupiter = Jupiter
data Earth = Earth

instance Collide Asteroid Planet where
    collide (Asteroid, Planet) = "an asteroid hit a planet"

instance Collide Asteroid Earth where
    collide (Asteroid, Earth) = "the end of the dinos"

-- Needs overlapping and undecidable instances
instance Collide a b => Collide b a where
    collide (a,b) = collide (b, a)

-- ghci output
*Collide> collide (Asteroid, Earth)
"the end of the dinos"
*Collide> collide (Earth, Asteroid)
"the end of the dinos"

这样做的目的是什么?

什么时候使用元组参数而不是多个参数更好?

4

2 回答 2

5

我几乎从不编写将元组作为参数的函数。如果出现变量固有连接的情况(如评论中提到的bheklilr),我更有可能将其打包成它自己的单独数据类型和模式匹配。

您可能想要定义一个将元组作为参数的函数的一种常见情况是,当您有一个Functor动态生成的元组列表(或任何任意),但想用某个函数映射它时,例如

grid :: [(Int, Int)]
grid = (,) <$> [1..10] <*> [1..10]

例如,您可能想要添加网格中所有元组的第一个和第二个值(无论出于何种原因),您可以通过将一个消耗元组的函数映射到grid

addTuple :: (Int, Int) -> Int
addTuple (x, y) = x + y

sumPoints :: [(Int, Int)] -> [Int]
sumPoints = map addTuple

在这种情况下我宁愿做的只是使用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
于 2014-07-09T15:30:56.467 回答
2

我会说,通常,函数应该被柯里化(所以没有元组),除了参数本身是元组。例如,如果你编写一个函数来添加两个数字,你有 2 个参数,所以你应该这样写:

add :: Num a => a -> a -> a
add x y = x + y

现在,如果由于某种原因您使用 2-uple 作为 2-D 点,并且您想添加两个点。直到两个参数,这似乎是元组,所以你会这样写

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-uples 列表)。在这种情况下,使用 uncurried 函数可能更容易,因此您可以对其进行映射。collide

于 2014-07-09T17:51:33.807 回答