2016-08-17 161 views
0

考慮從一組可能的字符串中生成字符串的問題,這樣一旦選擇字符串,就不能再次重複。對於這個任務,我想使用QuickCheckGen函數。使用QuickCheck從字符串池中生成隨機字符串

如果我看看我正在編寫的函數的類型,它看起來非常像狀態monad。由於我正在使用另一個monad,即Gen,在州monad中。我使用StateT寫了我的第一次嘗試。

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

其中:

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第一個元素的事實。其次,我的最終目標是爲JSON值定義一個隨機生成器,它使用資源池(不僅包含字符串)。使用StateT促使我實現QuickCheckelementslistOf

我想知道是否有實現這一目標的一個更好的辦法,或者這樣的複雜性是與生俱來的,以確定現有的單子的狀態變量的「狀態」的變種。

+0

我會以另一種方式來做 - 存儲創建的「字符串」 - 或者至少是種子,並比較每個種子/生成的字符串以獲得種子/字符串的「集合」中的成員資格。 – 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運行多個這樣的計算,同時共享的狀態。唯一合理的事情會生成多個隨機的唯一字符串連接在一起(使用相同的狀態)

evalStateT (replicateM 10 stringGenS) 

這是GenState -> Gen [String]類型。

+0

謝謝。 'lift'的使用絕對更加優雅。關於國家,正如我在我以前的評論中提到的那樣,由於我需要生成具有層次關係的數據,因此選擇一個元素會限制我未來的選擇,這就是爲什麼我想將狀態從一個生成器傳遞到另一個。字符串的生成只是說明性的。 –

+0

請注意'Gen'不會給你任何特別的分配。由於它用於閱讀,它試圖捕捉各種角落案例,而不是以任何方式統一。 –

+0

好點。我肯定需要在未來考慮這一點。這可能是我最終會使用「Random」monad。不過,我希望我可以用同樣的方法來編寫monad變形金剛。 –