2014-07-09 6 views
4

http://www.haskell.org/pipermail/haskell-cafe/2007-August/030096.html에서 typeclass 메서드 collide은 2 개의 "일반"인수가 아닌 하나의 인수로 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는 하스켈의 자동 작업이 필요하지 않는 한 항상 튜플을 사용하도록 권장합니다. curreying/uncurrying? – fadedbee

+2

내 _opinion_은 좌표가'(x, y) '인 튜플처럼 두 값이 본질적으로 연결된 경우 튜플을 사용해야한다는 것입니다. 다행히 2 튜플의 경우, 우리는 다른 하나보다 편리 할 때마다이 표현들 사이를 변환하는'카레'와'uncurry '를 가지고 있습니다. – bheklilr

답변

4

튜플을 인수로 사용하는 함수는 거의 작성하지 않습니다. 변수가 본질적으로 연결되어있는 상황이 발생하면 (예 : bheklilr이 주석에 언급 된 바와 같이) 나는 그 자체의 개별 데이터 유형과 패턴 일치를 상자에 넣을 확률이 높습니다.

당신이 즉시 생성 튜플의 목록 (또는 임의의 Functor)을 가지고 있지만, 그것을 통해 매핑 할 때 인수로 튜플을받는 함수를 정의 할을 할 수 있습니다 한 일반적인 상황은

어떤 기능, 예.

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

당신은, 말하자면, grid 통해 튜플이 소요되는 기능을 매핑하여 당신이 할 수있는, (어떤 이유) 그리드의 튜플 모두의 제 1 및 제 2 값을 추가 할 수 있습니다 :

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

I 것이라고 말하고, 일반적으로, 기능이 카레한다 (그래서 튜플). 예를 들어 두 개의 번호를 추가하는 기능을 작성하는 경우, 당신은 2 개 인자를 가지고, 그래서 당신은 그것을 작성해야 :

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

을 지금, 어떤 이유로 당신의 2-D 점으로 2 uple를 사용하는 경우, 그리고 두 점을 더하고 싶습니다. 그것은 당신이 당신이 다루는 기업이 튜플이기 때문에 정말 이해가되지 않을까요

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) 
add (x,y) (x,y') = (x+x', y+y') 

같이 작성합니다 있도록 튜플을 것으로 보인다 두 개의 인수까지입니다. 당신은 우리의 예에서 그 방법 중 하나

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

을 쓸 것, 그것은 것은 어쩌면 단계가 있기 때문에 (이 튜플로을 제공됩니다 확인할 때 collide 기능이 항상 컨텍스트에서 호출되는 가능성이있어하는 가능한 모든 충돌을 모아서 2-uples의 목록을 얻는다). 그런 상황에서는 덜컹 거리는 함수를 사용하는 것이 더 쉽기 때문에 collide을 그 위에 매핑 할 수 있습니다.