2014-07-09 1 views
4

В http://www.haskell.org/pipermail/haskell-cafe/2007-August/030096.html метод typeclass collide определяется как взятие 2-кортежа как его единственный аргумент, а не два «нормальных» аргумента (я думаю, что я понимаю частичное приложение и т. Д.).Когда функции Haskell принимают кортежи, а не несколько аргументов?

{-# 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" 

Какова цель этого?

Когда лучше использовать аргумент кортежа, а не несколько аргументов?

+0

Вы можете посмотреть на это: http://programmers.stackexchange.com/questions/185585/what-is-the-advantage-of-currying – Sibi

+0

@Sibi вы рекомендуете всегда использовать кортежи, если вам не нужна автоматическая система Haskell curreying/uncurrying? – fadedbee

+2

My _opinion_ - это то, что кортежи должны использоваться, когда два значения связаны по своей сути, например кортеж, представляющий координаты '(x, y)'. К счастью для 2-х кортежей, у нас есть 'curry' и' uncurry' для преобразования между этими представлениями, когда каждый из них более удобен, чем другой. – bheklilr

ответ

4

Я почти никогда не записываю функции, которые берут кортежи в качестве аргументов. Если возникает ситуация, когда переменные связаны по своей природе (как упоминается в 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 
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). В такой ситуации было бы легче, если бы у вас была некорректная функция, поэтому вы можете нанести на нее collide.

Смежные вопросы