2016-08-17 7 views
0

일단 문자열을 선택하면 다시 반복 할 수 없도록 가능한 문자열 집합에서 문자열을 생성하는 문제를 고려하십시오. 이 작업을 위해 QuickCheckGen 기능을 사용하고 싶습니다.QuickCheck을 사용하여 문자열 풀에서 임의의 문자열 생성

필자가 작성하려고하는 함수의 유형을 살펴보면 상태 모나드와 매우 유사하게 보입니다. 다른 모나드 즉, Gen을 상태 모나드에 사용하고 있습니다. 나는 StateT을 사용하여 나의 첫번째 시도를 썼다. 이 구현에 대해 나를 괴롭게

newtype GenState = St {getStrings :: [String]} 
    deriving (Show) 

removeString :: String -> GenState -> GenState 
removeString str (St xs) = St $ delete str xs 

stringGenS :: Gen (a, GenState) -> Gen (String, GenState) 
stringGenS genStSt = 
    genStSt >>= \(_, st) -> 
    elements (getStrings st) >>= \str -> 
    return (str, removeString str st) 

뭔가 내가 stringGenS의 첫 번째 요소를 사용하지 않는 사실이다 :

arbitraryStringS :: StateT GenState Gen String 
arbitraryStringS = 
    mapStateT stringGenS get 

. 둘째, 최종 목표는 JSON 값에 대한 임의의 생성기를 정의하는 것입니다.이 생성기는 리소스 풀 (문자열뿐 아니라)을 사용합니다. StateT를 사용하면 QuickCheckelements, listOf

내가 거기에 이것을 달성하는 더 좋은 방법, 또는 이러한 복잡성은 기존의 모나드의 상태 변종을 정의하는 고유인지 궁금 해서요의 "상태"변종을 구현하는 나를 이끌었다.

+0

생성 된'Strings' 또는 최소한 시드를 저장하고 seed /'String'의'Set' 멤버십에 대한 각 시드/생성 된 문자열을 비교하는 방법을 사용합니다. – epsilonhalbe

+0

다른 선택은 uuid를 사용하여 "가장 가능성있는"고유 문자열을 생성 할 수 있습니다. 문자열의 유한 집합 만있는 경우 - 결국 문자열이 부족하여 큰 기본 집합을 조합하여 해결할 수 있지만 여전히 실행됩니다. 중복 문자열에 - 당신이 "진정한 유일성"이 필요하다면 기본 세트 + 자연수와 같은 무한 집합을 가지고 결합 할 것입니다. – epsilonhalbe

+0

문자열이 리소스 풀에서 오는 것이 중요합니다. 이것은 일부 데이터베이스에있는 데이터를 사용하여 테스트를 생성하는 데 사용할 수 있습니다. –

답변

1

StateTGen의 조합은 다음과 같을 수 있습니다 :

import Control.Monad.State 
import Data.List (delete) 
import Test.QuickCheck 

-- A more efficient solution would be to use Data.Set. 
-- Even better, Data.Trie and ByteStrings: 
-- https://hackage.haskell.org/package/bytestring-trie-0.2.4.1/docs/Data-Trie.html 
newtype GenState = St { getStrings :: [String] } 
    deriving (Show) 

removeString :: String -> GenState -> GenState 
removeString str (St xs) = St $ delete str xs 

stringGenS :: StateT GenState Gen String 
stringGenS = do 
    s <- get 
    str <- lift $ elements (getStrings s) 
    modify $ removeString str 
    return str 

문제는 당신이 상태를 필요로하는 상태를 공유하면서, 당신은 Gen에서 여러 같은 계산을 실행할 수 있다는 것입니다. 할 수있는 유일한 합리적인 것은 유형 GenState -> Gen [String]이다

evalStateT (replicateM 10 stringGenS) 

로 (같은 상태를 사용하여) 함께 여러 임의의 고유 문자열을 생성하는 것입니다.

+0

감사. '리프트 '의 사용은 확실히 더 우아합니다. 국가에 관해서는 앞서 언급 한 것처럼 계층 적 관계가있는 데이터를 생성해야하기 때문에 하나의 요소를 선택하면 미래의 선택이 제한되어 그 이유 때문에 하나의 생성기에서 상태로 전달하려고합니다. 다른 하나. 문자열의 생성은 단순한 예시였습니다. –

+0

'Gen'는 당신에게 특별한 배포판을주지 않는다는 것을 알아 두십시오. 그것은 독서에 사용되는 것처럼 어떤 식 으로든 제복을 입히기보다는 다양한 구석을 잡으려고합니다. –

+0

좋은 지적. 나는 이것을 장래에 확실히 고려할 필요가있다. '랜덤'모나드를 사용하게 될지도 모릅니다. 그러나 모나드 변압기를 구성하는 동일한 기술을 사용할 수 있기를 바랍니다. –