2013-10-02 1 views
1

다음은 단순한 예제이며, 너무 많이 반복하지 않고 간단한 함수를 작성하는 데 문제가 있습니다. 필자가 작성하려고하는 실제 프로그램은 파이썬에서 BI 서버를위한 메모리 내 데이터베이스의 포트입니다. 실제로 Vector A와 같은 다형성 유형에서 작동하는 함수로 표현할 수있는 더 많은 다른 유형 (약 8 개)과 훨씬 더 많은 논리가 있지만 여전히 일부 논리는 다른 유형의 값을 처리해야합니다.기본 유형의 유한 도메인 컨테이너에 대한 동적 타이핑

[(Int, WrappedValue)] type을 사용하여 각 값을 분리하여 배치하는 것은 효율성상의 이유로 인해 옵션이 아닙니다. 실제 코드에서는 언 박싱 벡터를 사용하고 있습니다.

type Vector a = [(Int, a)] -- always sorted by fst 

data WrappedVector = -- in fact there are 8 of them 
     FloatVector (Vector Float) 
    | IntVector (Vector Int) 
    deriving (Eq, Show) 

query :: [WrappedVector] -> [WrappedVector] -- equal length 
query vectors = map (filterIndexW commonIndices) vectors 
    where 
     commonIndices = intersection [mapFstW vector | vector <- vectors] 

intersection :: [[Int]] -> [Int] 
intersection = head -- dummy impl. (intersection of sorted vectors) 

filterIndex :: Eq a => [Int] -> Vector a -> Vector a 
filterIndex indices vector = -- sample inefficient implementation 
    filter (\(idx, _) -> idx `elem` indices) vector 

mapFst :: Vector a -> [Int] 
mapFst = map fst 

-- idealy I whould stop here, but I must write repeat for all possible types 
-- and kinds of wrapped containers and function this: 

filterIndexW :: [Int] -> WrappedVector -> WrappedVector 
filterIndexW indices vw = case vw of 
    FloatVector v -> FloatVector $ filterIndex indices v 
    IntVector v -> IntVector $ filterIndex indices v 

mapFstW :: WrappedVector -> [Int] 
mapFstW vw = case vw of 
    FloatVector v -> map fst v 
    IntVector v -> map fst v 

-- sample usage of query 
main = putStrLn $ show $ query [FloatVector [(1, 12), (2, -2)], 
           IntVector [(2, 17), (3, -10)]] 

mapFstW 및 filterIndexW 함수처럼 래핑 및 래핑을 사용하지 않고 이러한 코드를 어떻게 표현할 수 있습니까? 그것은 단지 형 수준에서 차이를 만들기 때문에

답변

2

몇 가지 컴파일러 확장 프로그램을 사용하고자한다면 ExistentialQuantification이 문제를 잘 해결해줍니다.

{-# LANGUAGE ExistentialQuantification #-} 
{-# LANGUAGE StandaloneDeriving #-} 
module VectorTest where 

type PrimVector a = [(Int, a)] 

data Vector = forall a . Show a => Vector (PrimVector a) 

deriving instance Show Vector 

query :: [Vector] -> [Vector] -- equal length 
query vectors = map (filterIndex commonIndices) vectors 
    where 
     commonIndices = intersection [mapFst vector | vector <- vectors] 

intersection :: [[Int]] -> [Int] 
intersection = head -- dummy impl. (intersection of sorted vectors) 

filterIndex :: [Int] -> Vector -> Vector 
filterIndex indices (Vector vector) = -- sample inefficient implementation 
    Vector $ filter (\(idx, _) -> idx `elem` indices) vector 

mapFst :: Vector -> [Int] 
mapFst (Vector l) = map fst l 

-- sample usage of query 
main = putStrLn $ show $ query [Vector [(1, 12), (2, -2)], 
           Vector [(2, 17), (3, -10)]] 

벡터에 대한 수동 Show 인스턴스를 작성하는 경우 StandaloneDeriving 요구 사항을 제거 할 수 있습니다.

+0

이 문제는 실제 문제에 잘 맞습니다 (Data.Typeable의 도움으로). 감사합니다. –

+0

다행스럽게도 도움이되었습니다. –

1

성능 저하없이 단일 유형을 포장에 대한 표준 옵션은

{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- so we can derive Num 
newtype MyInt = My Int deriving (Eq,Ord,Show,Num) 
newtype AType a = An a deriving (Show, Eq) 

을하는 것입니다 - 모든 멀리 컴파일 도착하기 때문에 데이터 표현은 동일하다. 값을 unboxed로 지정할 수도 있지만, 여러 유형을 래핑하기 때문에 여기서는 도움이되지 않습니다.

실제 문제는 정적 형식의 언어로 동적 유형의 솔루션을 나타내려고한다는 것입니다. 동적 언어로는 숨겨져 있지만 태그 지정에서는 여기에 명시된 동적 입력에 대해 반드시 성능이 저하됩니다.

  1. 가 동적 타이핑이 정적 입력을 통해 추가 런타임 검사를 포함에 동의하고 추악한 살 :

    당신은 두 가지 솔루션이있다.

  2. 다이내믹 타이핑 (dynamic typing)의 필요성을 배제하고, 다형성 타이핑 (polymorphic typing)이 모든 코드를 정돈하고 유형 검사를 컴파일 시간 및 데이터 획득으로 옮깁니다.

나는 2가 훨씬 좋은 솔루션이라고 생각하며, 사용하려는 모든 유형의 프로그램을 나열하는 대신 모든 유형을 사용하도록 프로그래밍하는 것을 포기해야합니다. 그것은 깔끔하고 명확하며 효율적입니다. 유효성을 확인하고 한 번 처리 한 다음 걱정할 필요가 없습니다.

관련 문제