Подтвердить что ты не робот

Haskell quickcheck - как сгенерировать только печатные строки

У меня есть набор простых демо-программ, которые кодируют/декодируют строки и хотят сгенерировать для них несколько тестов QuickCheck, но ограничивать тесты только печатными строками. Использование защиты слишком медленное и не выполняется из-за слишком большого количества сгенерированных и отклоненных тестовых примеров, поэтому я хочу создать безопасный генератор для этого домена.

Ссылки на это, которые я видел, говорят, что (1) определяют один собственный произвольный экземпляр для Char и используют его для генерации только печатаемых символов для строк или (2) для обертывания самих функций в newtype и написать для него произвольный экземпляр.

Но попытка сделать (1) не удается, потому что в Test.QuickCheck есть определение для этого, и как бы это сделать - создать генератор safeChar для нового типа, а затем снова создать адаптер для проверенные функции? (В разделе книги RWH об этом отмечается, что он устарел, рекомендуя это определение DIY Char.)

Попытка сделать (2) кажется, что я могу либо добавить защитника в тестовое предложение, которое является локализованным и простым (но не работает), либо написав новую оболочку и связанный с ней генератор, который кажется более беспорядочным.

Ясно, что это просто (!), и все инструменты предоставлены, но кто-то может посоветовать, правильно ли это это сделать, и дать пример того, как лучше всего это сделать?

4b9b3361

Ответ 1

Отправной точкой является генератор genSafeChar, который может иметь тип Gen Char. Например:

genSafeChar :: Gen Char
genSafeChar = elements ['a'..'z']

Затем вы можете построить это в генератор genSafeString, например. с listOf:

genSafeString :: Gen String
genSafeString = listOf genSafeChar

На этом этапе у вас есть несколько разумных вариантов. Создайте обертку newtype для String:

newtype SafeString = SafeString { unwrapSafeString :: String }
    deriving Show

instance Arbitrary SafeString where
    arbitrary = SafeString <$> genSafeString

(в этом случае вы можете просто вставить определение genSafeString)

и вы можете использовать его примерно так:

testWibble (SafeString str) = str == str

Или вы можете использовать forAll в каждой точке, где вам нужна безопасная строка:

testWibble = forAll genSafeString $ \str -> str == str