我正在尝试为我的数据类型编写一个修改过的Arbitrary
实例,其中(在我的例子中)一个子组件的类型为[String]
。理想情况下,我希望在实例本身中带来唯一性,这样我每次编写的测试都不需要==>
标题/先决条件。
这是我的数据类型:
data Foo = Vars [String]
和简单的Arbitrary
实例:
instance Arbitrary Foo where
arbitrary = Vars <$> (:[]) <$> choose ('A','z')
这个例子很奇怪,我知道。在过去,我在快速检查组合爆炸时遇到了困难,所以我想保持这些值很小。另一个请求 - 如何创建一个实例,其中生成的字符串小于4个字符,例如?
所有这些,从根本上要求(布尔)谓词来扩充Arbitrary
个实例。这可能吗?
答案 0 :(得分:2)
suchThat :: Gen a -> (a -> Bool) -> Gen a
是一种在Gen
中嵌入布尔谓词的方法。有关详细信息,请参阅haddocks。
以下是如何使实例具有唯一性:
instance Arbitrary Foo where
arbitrary = Vars <$> (:[]) <$> (:[]) <$> choose ('A','z')
`suchThat` isUnique
where
isUnique x = nub x == x
答案 1 :(得分:2)
当然,您希望实例仅生成与数据类型意图相匹配的实例。如果您希望所有变量都是不同的,Arbitrary
实例必须反映这一点。 (另一个问题是,如果在这种情况下将Vars
定义为集合(例如newtype Vars = Set [String]
)会更有意义。)
我建议使用Set
或Hashtable
检查重复项,因为nub
具有 O(n ^ 2)复杂度,这可能会减慢速度对于较大的输入,您的测试相当例如:
import Control.Applicative
import Data.List (nub)
import qualified Data.Set as Set
import Test.QuickCheck
newtype Foo = Vars [String]
-- | Checks if a given list has no duplicates in _O(n log n)_.
hasNoDups :: (Ord a) => [a] -> Bool
hasNoDups = loop Set.empty
where
loop _ [] = True
loop s (x:xs) | s' <- Set.insert x s, Set.size s' > Set.size s
= loop s' xs
| otherwise
= False
-- | Always worth to test if we wrote `hasNoDups` properly.
prop_hasNoDups :: [Int] -> Property
prop_hasNoDups xs = hasNoDups xs === (nub xs == xs)
然后您的实例需要创建一个列表列表,每个列表都应该是随机的。因此,您需要两次调用(: [])
,而不是只创建单个列表(只有一个级别)的listOf
,而不是instance Arbitrary Foo where
arbitrary = Vars <$> (listOf . listOf $ choose ('A','z'))
`suchThat` hasNoDups
。{/ p>
choose ('A', 'z')
另请注意,oneof [choose ('A','Z'), choose ('a','z')]
允许使用 A 和 z 之间的所有字符,其中包含许多控制字符。我的猜测是你想要像
hasNoDups
如果您真的想要,也可以使用hash tables monad中的ST
Gen Foo
O(n)。
关于限制大小:你总是可以拥有自己的参数化函数来产生不同的Gen
,但我会说在大多数情况下它没有必要。 listOf
有自己的内部大小参数,在整个测试过程中会增加(参见this answer),因此涵盖了不同的大小(使用Var
生成)。
但我建议你实施shrink
,因为这会给你更好的反例。例如,如果我们定义(错误的测试),试图验证prop_Foo_hasNoDups :: Foo -> Property
prop_Foo_hasNoDups (Vars xs) = all (notElem 'a') xs === True
的任何实例在其任何变量中都不包含'a':
Vars ["RhdaJytDWKm","FHHhrqbI","JVPKGTqNCN","awa","DABsOGNRYz","Wshubp","Iab","pl"]
我们会得到丑陋的反例,例如
shrink (Vars xs) = map Vars $ shrink xs
但添加
Arbitrary Foo
到Vars ["a"]
使得反例只是
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
Chart chart2 = new Chart();
Chart chart3 = new Chart();
int[] rand;
int[] rand1;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
chart2.Width = 1000 ;
chart2.Height = 200;
this.Controls.Add(chart2);
this.Controls.Add(chart3);
chart2.MouseMove += new MouseEventHandler(chart2_MouseMove);
//chart2.GetToolTipText += new EventHandler<ToolTipEventArgs>(chart2_GetToolTipText);
chart2.ChartAreas.Add("Area");
chart2.ChartAreas[0].CursorX.AutoScroll = true;
chart2.ChartAreas[0].CursorX.Interval = 1;
chart2.ChartAreas[0].AxisX.LabelAutoFitStyle = LabelAutoFitStyles.None;
chart2.ChartAreas[0].AxisX.IsStartedFromZero = true;
chart2.ChartAreas[0].AxisX.Minimum = 0;
chart2.ChartAreas[0].AxisX.ScaleView.SizeType = DateTimeIntervalType.Number;
chart2.ChartAreas[0].AxisX.MajorTickMark.Interval = .5;
chart2.ChartAreas[0].AxisX.ScrollBar.IsPositionedInside = true;
chart2.ChartAreas[0].AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
chart2.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = 100;
chart2.ChartAreas[0].AxisX.ScrollBar.Enabled = true;
chart2.ChartAreas[0].AxisY.IsStartedFromZero = true;
int[] X = new int[100];
for (int i = 0; i < 50; i++)
{
X[i] = i+1;
}
int[] Y = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
chart2.Series.Add("Alpha");
chart2.Series.Add("Beta");
chart2.Series["Alpha"].ChartType = SeriesChartType.Line;
chart2.Series["Beta"].ChartType = SeriesChartType.Line;
chart2.Series["Alpha"].Color = Color.Blue;
chart2.Series["Beta"].Color = Color.DarkGreen;
chart2.Series["Alpha"].XValueType = ChartValueType.Double;
chart2.Series["Beta"].XValueType = ChartValueType.Double;
//chart2.Series[0].
chart2.Series["Alpha"].YValueType = ChartValueType.Double;
chart2.Series["Beta"].YValueType = ChartValueType.Double;
Legend leg = new Legend();
chart2.Legends.Add(leg);
chart2.Legends[0].Alignment = StringAlignment.Near;
Random _r = new Random();
rand = new int[1000];
rand1 = new int[1000];
for (int i = 0; i < X.Length; i++)
{
int n = _r.Next(0, 100);
rand[i] = n;
chart2.Series["Alpha"].Points.AddY(n);
}
for (int i = 0; i < X.Length; i++)
{
int n = _r.Next(0, 100);
rand1[i] = n;
chart2.Series["Beta"].Points.AddY(n);
}
chart2.Series[0].ToolTip = "X = #VALX, Y= #VALY";
chart2.Series[1].ToolTip = "X = #VALX, Y= #VALY";
}
private void chart2_Click(object sender, EventArgs e)
{
}
private void chart2_MouseMove(object sender, MouseEventArgs e)
{
HitTestResult htr = this.chart2.HitTest (e.X, e.Y);
Point p = new Point(e.X, e.Y);
int K = Convert.ToInt32(p.X);
chart2.ChartAreas[0].CursorX.Interval = 0;
chart2.ChartAreas[0].CursorX.SetCursorPixelPosition(p,true);
//chart2.ChartAreas[0].CursorY.SetCursorPixelPosition(p, true);
//Label Xlbldisplay = new Label();
//Xlbldisplay.Text = "X";
//Label Ylbldisplay = new Label();
//Ylbldisplay.Text = "Y";
chart2.Series[0].ToolTip = "X = #VALX, Y= #VALY";
//string p = chart2.GetToolTipText;
if (Convert.ToInt32(chart2.ChartAreas[0].CursorX.Position) <= 1000)
{
aXdisplay.Text = Convert.ToString(Convert.ToInt32(chart2.ChartAreas[0].CursorX.Position));
aYdisplay.Text = Convert.ToString(rand[Convert.ToInt32(aXdisplay.Text)]);
bXdisplay.Text = aXdisplay.Text;
bYdisplay.Text = Convert.ToString(rand1[Convert.ToInt32(aXdisplay.Text)]);
}
}
//private void chart2_GetToolTipText(object sender, ToolTipEventArgs e)
//{
// HitTestResult rt = chart2.HitTest(e.X, e.Y);
// if(rt.ChartElementType == ChartElementType.DataPoint)
// {
// Xdisplay.Text = chart2.Series[0].Points[rt.PointIndex].XValue.ToString();
// Ydisplay.Text = chart2.Series[0].Points[rt.PointIndex].YValues[0].ToString();
// }
// //Ydisplay.Text = e.Y.ToString();
//}
//private void chart2_CursorPositionChanged(object sender, CursorEventArgs e)
//{
// //HitTestResult htr = this.chart2.HitTest(e.X, e.Y);
// //Point p = new Point(e.X, e.Y);
// //chart2.ChartAreas[0].CursorX.Interval = 0;
// //chart2.ChartAreas[0].CursorX.SetCursorPixelPosition(p, true);
// //chart2.ChartAreas[0].CursorY.SetCursorPixelPosition(p, true);
//}
}