Я хотел бы сгенерировать произвольное значение для упорядоченной древовидной структуры, тип которой, скажем,
data Tree a = Leaf | Node (Tree a) a (Tree a)
Функция, которая вставляет значение в это дерево, сохраняя его упорядоченным, потребует, чтобы это значение было Ord. Но для создания упорядоченных деревьев для произвольного экземпляра мне нужно было бы сгенерировать значение в диапазоне «[low, hi]», а Ord для этого недостаточно. Поэтому я также потребовал, чтобы значение было Enum, поскольку Enum позволяет получать значения из заданной границы. Для choose
ниже также требуется System.Random.Random:
import Test.QuickCheck.Arbitrary
import System.Random
generateTree :: (Arbitrary a, Ord a, Enum a, Random a) => a -> a -> Gen (Tree a)
generateTree l u = do
genLeaf <- arbitrary
if genLeaf
then return Leaf
else do
x <- choose (l, u)
left <- generateTree l (pred x)
right <- generateTree (succ x) u
return $ Node left x right
Поэтому, чтобы использовать это для реализации arbitrary
, мне нужны те же классы в произвольном классе:
instance (Arbitrary a, Ord a, Enum a, Rand.Random a) => Arbitrary (Tree a) where
arbitrary = do
l <- arbitrary
u <- arbitrary
generateTree l u
Здесь, хотя требования Ord a => Tree a
достаточно для самой структуры данных, мне требуется (Arbitrary a, Ord a, Enum a, Rand.Random a) => Tree a
для ее генератора. Это похоже на утечку деталей реализации в декларацию - возможно, я смотрю на это неправильно, я изучаю Haskell. Но все же есть вопросы:
- Есть ли способ объявить более общий генератор, у которого не так много требований?
- Есть ли способ объявить другой экземпляр для
Arbitrary (Tree a)
вместе с указанным выше, который будет иметь другой набор требований, что-то вродеArbitrary (Tree Int)
, который будет использоваться только дляInt
?
Arbitrary
дляa
и не требуется доступ к реализации этих операций. - person Cirdec   schedule 23.03.2015