Как я могу ограничить параметры QuickCheck, например. использовать только неотрицательные целые числа?

Я новичок в Хаскеле. Пока это очень хорошо, но я сталкиваюсь с копированием и вставкой для моих свойств QuickCheck, и я хотел бы это исправить.

Вот готовый пример:

prop_Myfunc :: [Int] -> (Int,Int) -> Bool
prop_Myfunc ints (i,j) = ints !! i == ints !! j

Это не сработает, потому что QuickCheck генерирует отрицательные числа, поэтому я получаю

*** Failed! (after 2 tests and 2 shrinks):                               
Exception:
  Prelude.(!!): negative index

Я пытался найти решения для этого в Google, и я нашел, например. Неотрицательный и ==> , но я не понимаю, как они работают.

Как я могу ограничить приведенный выше пример, чтобы i и j никогда не были отрицательными? И еще, чтобы ни было слишком высоко? То есть: 0 <= i,j < length ints


person Joel Hinz    schedule 27.11.2014    source источник
comment
Я думаю, вы имеете в виду 0 <= i,j < length ints   -  person ErikR    schedule 27.11.2014
comment
@ user5402 Да, спасибо! Я изменю это. Проверю ваш ответ, как только смогу, он выглядит очень хорошо.   -  person Joel Hinz    schedule 27.11.2014


Ответы (3)


Ограничивающие оболочки (из Test.QuickCheck.Modifiers, если они не реэкспортируются неявно) можно использовать следующим образом:

prop_Myfunc :: [Int] -> (NonNegative Int, NonNegative Int) -> Bool
prop_Myfunc ints (NonNegative i, NonNegative j) = ints !! i == ints !! j

Вы можете рассматривать SomeWrapper a как a с измененным дистрибутивом. Например, NonNegative a гарантирует, что a >= 0. После создания оболочки значение можно получить с помощью сопоставления с образцом или явного доступа (в данном случае getNonNegative).

Что касается ограничения верхнего поля ваших индексов, я думаю, что это невозможно с обертками (в системе типов Haskkell невозможно параметризовать тип значением, в данном случае длиной списка). Однако с помощью оператора ==> вы можете добавить произвольное логическое ограничение для своего теста:

prop_Myfunc ints (NonNegative i, NonNegative j) = i < l && j < l ==> ints !! i == ints !! j where
    l = length ints

Он работает по-другому: когда условие не выполняется, он просто отбрасывает текущий тестовый пример. Но будьте осторожны: если выброшенных случаев слишком много (условие слишком ограничительное), тест становится гораздо менее полезным. Поведения «без потерь» часто можно добиться с помощью shrinkобработки тестовых данных, но это совсем другая тема.

person Yuuri    schedule 27.11.2014
comment
Благодарю вас! Это именно то, что мне было нужно. - person Joel Hinz; 27.11.2014

Во-первых, см. этот ответ SO для примера того, как написать пользовательскую функцию Gen ... и как использовать комбинатор forAll.

А вот как написать генератор для непустого списка и двух допустимых неотрицательных индексов в список:

import Test.QuickCheck

genArgs :: Gen ( [Int], Int, Int )
genArgs = do
  x <- arbitrary
  xs <- arbitrary
  let n = length xs
  i <- choose (0,n)
  j <- choose (0,n)
  return ( (x:xs), i, j) -- return a non-empty list

test = quickCheck $ forAll genArgs $ \(xs,i,j) -> prop_myfunc xs (i,j)
person ErikR    schedule 27.11.2014
comment
Большое тебе спасибо. Я многому научился благодаря этому. Ответ Юри больше соответствовал тому, что я хотел, но я хотел бы принять его. По крайней мере, проголосуйте. - person Joel Hinz; 27.11.2014
comment
На самом деле, мне это решение нравится больше, чем мое собственное :) - person Yuuri; 28.11.2014

Я был в такой же ситуации, как и вы, и наконец нашел, как использовать ==> здесь: http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html в разделе «Условные свойства».

В вашем примере вам нужно будет заменить Bool на Property и вставить требования к вашим переменным перед проверкой свойства следующим образом:

prop_Myfunc :: [Int] -> (Int,Int) -> Property
prop_Myfunc ints (i,j) = (i >= 0 && j >= 0) ==> ints !! i == ints !! j

(Я не тестировал этот конкретный пример, но у меня это сработало в аналогичном случае.)

Обратите внимание на тип ==>: (==>) :: Testable prop => Bool -> prop -> Property.

person bli    schedule 05.08.2016