2010-05-27 6 views

답변

39

를 일반적인 방법으로, 당신은 할 수 없습니다. 튜플의 각 크기는 별개의 형식 인 반면, 길이의 목록은 단일 유형입니다. 따라서 목록을 취하고 같은 길이의 튜플을 반환하는 함수를 작성하는 좋은 방법은 없습니다.이 함수는 잘 정의 된 반환 유형이 아닙니다. 모두의 작업을 수행 한

tuplify2 :: [a] -> (a,a) 
tuplify2 [x,y] = (x,y) 

tuplify3 :: [a] -> (a,a,a) 
tuplify3 [x,y,z] = (x,y,z) 

...하지만 :

는 예를 들어, 같은 기능을 가지고있다.

은 다양한 종류의 메타 프로그래밍을 사용하여 일반 버전을 작성하지만 거의 원하지 않을 수 있습니다.

동일한 문제가 다양한 튜플에 대한 클래스 인스턴스 작성과 같은 다른 문제에 적용된다는 점에 유의하십시오. 표준 라이브러리의 the source code for Data.Tuple을 살펴보십시오!

+0

이것이 어떻게'Data.Tuple'의 실제 소스가 될 수 있습니까? 내 말은 ... 수출 목록의 두 번째 요소는', snd - :: (a, b) -> a'입니다. 정말로 거기에 유형에이 눈부신 오류가 있습니까? – Bakuriu

+2

@Bakuriu : 하, 재미있는 오타입니다. 물론 주석 일뿐입니다. 파일 끝에있는'snd'의 타입 서명이 맞습니다. 그것도 상당히 오래된 버전의'Data.Tuple'이며, 최신 버전에는 그 오류가 없습니다. –

6

튜플과 목록은 매우 다른 것들입니다. 목록의 하나의 변수는 튜플 여섯 개 변수로 확장 : 유형이 얼마나 다른

toTuple :: [a] -> (a,a,a,a,a,a) 
toTuple [a,b,c,d,e,f] = (a,b,c,d,e,f) 

공지 사항 : 당신이 할 수있는 최선의 정보를 수동으로 변환 기능을 작성하는 것입니다. 따라서 각 튜플 크기에 대해 하나의 함수가 필요합니다.

+1

너와 캠컨이 나를 때렸다. 그게 가능합니다, 그가 할 수있는 최선은 N 함수입니다. 주어진 N에 대해 이것들 중 하나를 호출하는 핸들러입니다. – Spidey

+0

@ Spidey : Template Haskell을 사용하는 법을 배우십시오! –

+0

튜플은 수학의 목록입니다. 그들은 매우 유사합니다. Haskell의 구현에서 튜플은 고정 된 형식의 길이를 가지고 있으므로 목록을 변환 할 수 없으므로 둘을 변환하는 것은 쉽지 않지만 언어 별 구현 문제입니다. – clay

2

준 인용 (quasi-quotation) [1]을 사용하는 경우 튜플 크기 당 하나의 함수를 수동으로 작성하는 것보다 실제로 더 잘 수행 할 수 있습니다. 그러나 일반적으로이 코드를 사용할 코드에 대해서는 궁금 할 것입니다.

[1] http://www.haskell.org/haskellwiki/Quasiquotation

+0

시간이 있고 그걸로 내 의견을 편집 할 때 오늘 나중에 약간의 예제를 작동하도록 기대 ... – StevenC

+2

Quasiquotation 템플릿 하스켈의 일부로, 내가 믿는, 내가 언급 한 메타 프로그래밍입니다. 결국 이것은 튜플 크기마다 하나의 함수를 생성합니다. 단지 손으로 직접 작성하는 대신 컴파일 타임 코드를 작성하는 것입니다. 나는 TH의 걸음을 아직받지 못했습니다. 그래서 나는 당신의 모범을 보길 고대합니다! –

+0

Edward Kmett가 나를 때렸다. 전에 quasiquotes로 해봤다고 생각했지만, 그것은 TH 일 것 같아요. 죄송합니다. – StevenC

23
하스켈하면되기 때문에, 소자의 가변 수를 추출 할 것인지를 확인 입력 인해 얻을 수있는 한 가까운

템플릿 (a, b) 및 (A, B, C) 다른 유형이 있습니다. 그런 다음

{-# LANGUAGE TemplateHaskell #-} 
import Language.Haskell.TH 
tuple :: Int -> ExpQ 
tuple n = do 
    ns <- replicateM n (newName "x") 
    lamE [foldr (\x y -> conP '(:) [varP x,y]) wildP ns] (tupE $ map varE ns) 

:

$(tuple 6) [1,2,3,4,5,6] == (1,2,3,4,5,6) 
$(tuple 3) "abc" == ('a','b','c') 

그러나 당신이 대답을해야하는 경우 일반적으로, 당신은 어딘가 잘못된 질문을하고

.

플랫 무작위 액세스 만하려는 경우 더 나은 옵션은 배열을 사용하는 것입니다.

+3

템플릿 하스켈은 훌륭하지만, 조금 더 읽기 쉬웠 으면 좋겠습니다. 다시 말하지만, 아마도 그렇지 않은 것이 가장 좋습니다. 그렇지 않으면 사람들이 실제로 사용해야하는 것보다 더 많이 사용하게 될 것입니다. –

+0

분명히'Control.Lens'는'map (^ .. each)'와 더 가까워지고, 이는 임의의 튜플에도 적용됩니다. - "임의의 튜플의 경우"가 아닌 튜플의 모든 부분과 관련이있는 것은 아닙니다. – Evi1M4chine

+0

'each'가 게으른 패턴을 사용하는 방식으로 인해 : 'ghci> undefined & parts of each. ~ [1,2, 3,4] :: (Int, Int, Int, Int) '는 (1,2,3,4)입니다. 두 가지 방법으로 최대 크기 9 정도까지 갈 수 있습니다. 물론 결과 튜플 유형을 알아야합니다. –

3

나는 컴파일 타임에 알려지지 않은 임의의 길이의 목록을 위해 하스켈에서 이것을 할 수 있다고 생각하지 않는다. Haskell은 컴파일시에만 동작하기 때문에 그것을 할 수 없다. 나는 정확하게 이것을 할 필요가있는 경우를 만났고 나는 그 문제를 해결해야만했다. 데이터베이스 라이브러리는 쿼리 인수에 대해 다른 길이의 튜플을 예상하지만 임의 길이의 목록이 있습니다. 그래서 도서관 인터페이스를 둘러 봐야합니다. 목록을 가져 가면 좋을 것입니다.

기본적으로 길이가 다른 튜플은 다른 유형입니다. 그러나 하스켈 컴파일러는 런타임에 존재할 수있는 유형을 컴파일 유형에서 알아야합니다. 임의의 길이의리스트를 런타임에 터플로 변환하면 컴파일 타임에 알지 못하는 타입을 만들 수 있습니다.

4

나는 어려운 템플릿 하스켈 조작의 설득력있는 설명을 찾을하지만, 여기 데모입니다 :

> :m +Language.Haskell.TH 
> :set -XTemplateHaskell 
> runQ [| [1,2,3,4,5,6] |] >>= putStrLn . pprint 
[1, 2, 3, 4, 5, 6] 
> runQ [| [1,2,3,4,5,6] |] >>= \ (ListE exps) -> putStrLn (pprint (TupE exps)) 
(1, 2, 3, 4, 5, 6) 
8

느낌 나는 당신의 발에 총을 가리 키도록 조언하고 당신을하지 신뢰에 대한 생각과 같은 경우 촬영합니다.

> list2Tuple lst = read $ "(" ++ (init.tail.show) lst ++ ")" 
> list2Tuple [1,2,3] :: (Int, Int, Int) 
(1,2,3) 
> list2Tuple [1,2,3,4] :: (Int, Int, Int, Int) 
(1,2,3,4) 

이렇게하면 표시 및 읽기 튜플의 길이를 정의 할 수 있습니다.

관련 문제