Если я чего-то не упускаю, ваша Eq
реализация RoseT
такая же, как производная реализация по умолчанию. Так что ты можешь просто сказать
data RoseT a = Leaf a | Node a [RoseT a] deriving (Show, Eq)
и забудьте про instance Eq (RoseT a) where
вещи.
Следующий вопрос: удовлетворит ли это ваши потребности в тестировании. Если вы тестируете параметр типа с плавающей запятой, например RoseT Double
, вам необходимо учитывать различия из-за округления. В этом случае вам нужна функция, которая сравнивает два дерева и проверяет, являются ли значения «достаточно близкими».
Однако я подозреваю, что ваша реализация RoseT
никоим образом не будет зависеть от параметра типа. В этом случае вы можете просто протестировать его с помощью простого простого типа, такого как Char
или Int
, и использовать ==
для любых необходимых вам сравнений.
У вас есть две подписи типа для appendPath
. Думаю, второй должен был быть appendPath'
:
appendPath' :: [a] -> (RoseT a) -> (RoseT (a,[a]))
Теперь о том, как это проверить. Было бы лучше, если бы вы / QuickCheck имели некоторый контроль над сложностью тестируемых деревьев. Это поможет вам, потому что в первую очередь будут проверены простейшие деревья, поэтому вы обнаружите ошибки «на раннем этапе» (то есть в более простых тестовых примерах, которые легче отлаживать). Вы можете сделать это, реализовав для своего класса генератор «определенного размера». Вот один из способов сделать это. Чем выше значение параметра «размер», тем больше уровней может иметь дерево.
type TestRoseT = RoseT Char
sizedArbTestRoseT :: Int -> Gen TestRoseT
sizedArbTestRoseT 0 = do
c <- arbitrary
return $ Leaf c
sizedArbTestRoseT n = do
c <- arbitrary
subtreeCount <- choose (0,n-1)
subtrees <- vectorOf subtreeCount (sizedArbTestRoseT (n-1))
return $ Node c subtrees
instance Arbitrary TestRoseT where
arbitrary = sized sizedArbTestRoseT
prop_appendPath_does_something :: TestRoseT -> Property
prop_appendPath_does_something t = undefined -- stub
Мы можем выбрать тестовые данные, которые сгенерированы следующим образом:
λ> sample (sizedArbTestRoseT 2)
Node '\a' [Node '\RS' []]
Node '?' []
Node '\158' []
Node 'o' [Node 'E' []]
Node '\196' []
Node '4' [Node 'G' []]
Node ';' [Node 'f' []]
Node 'A' [Node '\CAN' []]
Node '!' []
Node 'q' [Node '\t' []]
Node '\'' [Node '\212' []]
Редактировать:
Для вашего типа Expr
мы можем написать такой генератор:
sizedArbExpr :: Int -> Gen Expr
sizedArbExpr 0 = do
s <- arbitrary
return $ Var s
sizedArbExpr n = do
es <- vectorOf 2 (sizedArbExpr (n-1))
elements [AddExpr es, MulExpr es]
instance Arbitrary Expr where
arbitrary = sized sizedArbExpr
Нам нужно будет изменить TestRoseT
и его генератор так, чтобы сложность дерева согласовывалась с параметром size:
type TestRoseT = RoseT Expr
sizedArbTestRoseT :: Int -> Gen TestRoseT
sizedArbTestRoseT 0 = do
c <- sizedArbExpr 0 -- changed this to keep complexity in bounds
return $ Leaf c
sizedArbTestRoseT n = do
c <- sizedArbExpr (n-1) -- changed this to keep complexity in bounds
subtreeCount <- choose (0,n-1)
subtrees <- vectorOf subtreeCount (sizedArbTestRoseT (n-1))
return $ Node c subtrees
Тестирование этих модификаций дает что-то вроде:
λ> sample (sizedArbTestRoseT 3)
Node (MulExpr [MulExpr [Var "",Var ""],AddExpr [Var "",Var ""]]) [Node (MulExpr [Var "",Var ""]) [Node (Var "") []]]
Node (MulExpr [AddExpr [Var "",Var ""],AddExpr [Var "",Var ""]]) [Node (AddExpr [Var "",Var ""]) []]
Node (MulExpr [AddExpr [Var "\164D",Var "\151\246\FS"],MulExpr [Var ":\149j\EM",Var "h\253\255"]]) [Node (MulExpr [Var "\CAN\a\ACK",Var "\184"]) [Node (Var "t\154]\\") []],Node (MulExpr [Var "\135",Var "\f\DEL\\"]) [Node (Var "\SOH\DEL") []]]
Node (AddExpr [AddExpr [Var "",Var ""],MulExpr [Var "Kj\STXV",Var "D\141<s\187"]]) []
Node (AddExpr [MulExpr [Var "\252",Var "`"],MulExpr [Var "\167`t\196",Var ":\135\NULdr\237\167"]]) []
Node (AddExpr [MulExpr [Var "]\173\&28D\SOCom",Var "^\196\ETB2\216\&2\GS\ENQ\ENQ"],AddExpr [Var "$bB\212\SOH\146\234",Var "\DC3\213\&3\SUB\\}^\246(\200"]]) [Node (MulExpr [Var "l;\133\EM\147#\SUBN\\\t",Var "\235\151U\129m3|"]) [Node (Var "\NULb\133") []],Node (AddExpr [Var "\187\EOT\165S\207\r\"\RS",Var "4"]) []]
Node (MulExpr [MulExpr [Var "%0eK",Var "`N**k\FS6\NAK"],MulExpr [Var "'lUL\NAKRPc\ENQR",Var "j\232+`\FS@n"]]) [Node (AddExpr [Var "H\DC1C%\DC48<\t\ETX.L",Var "\235+\v\STXX,\NAK\SUBQc="]) [Node (Var "f\254oX?w\224\195~/") []]]
Node (AddExpr [AddExpr [Var "P",Var "\148G\STX\DEL*\136(\161\159\&7"],AddExpr [Var "\218\136-",Var "9?\128\159\b\b%3t}\131qe"]]) [Node (MulExpr [Var "\198\249\&4\176\193/}\DC28",Var ")Gl0ym\GS"]) [Node (Var ")\204\226qA\175") []]]
Node (MulExpr [MulExpr [Var "\t\186r.",Var "j\ENQ\183\NUL\NAK\129:rg[\170o\157g\238"],AddExpr [Var "\218F\226\248\156\225\&1",Var "vu\SOH\138+CKW\EM\167\&1n"]]) [Node (MulExpr [Var ",\241\158={o\182\"5\t\STX\ETX\DC2\218\162",Var "\197\&1"]) [Node (Var "u?a};\238") []]]
Node (MulExpr [MulExpr [Var "*",Var "R"],AddExpr [Var "\CAN8C",Var "\232V.\172ILy\162a"]]) []
Node (MulExpr [MulExpr [Var "\SI\240NF\249-\v$",Var "K`\STX\231w{"],MulExpr [Var "\DC1\255\209",Var "/\227\146\236\STX\185T3r\f"]]) [Node (MulExpr [Var "\229,\DLE\NAKwf[7P\160\DEL",Var "\134#\RS\SI0KCg\195\NAK\"\191\&6\243\193\SI"]) [Node (Var "\226\&7b8\f\EOTgF\171\GS}\189c\SUBc\ETX") []]]
Кстати, вы сказали: «Кажется, невозможно написать генератор, который принимает параметр типа в качестве аргумента». На самом деле это возможно, но я не думаю, что это то, что вам действительно нужно.
Между прочим, кажется немного необычным, что вы хотите создать дерево (RoseT
), где листья содержат двоичные деревья (Expr
). Другими словами, вы создаете деревья из деревьев. Конечно, я не знаю вашего приложения.
person
mhwombat
schedule
12.07.2013
RoseT
определение кажется неверным. Розовые деревья не должны иметьLeaf
шаблон в ADT, поскольку с этим определением неоднозначно, должны ли листовые узлы записываться какLeaf 42
илиNode 42 []
. Это неоднозначно, потому что эти два выражения должны быть равны, но это не так. - person Daniel Dinnyes   schedule 18.03.2019