まず始めにsndBigger
- これは非常に単純な関数ですが、保持するプロパティをいくつか書くことができます。たとえば、タプルの値を逆にするとどうなるか:
// Reversing values of the tuple negates the result
let swap (a, b) = (b, a)
let prop_sndBiggerSwap x =
sndBigger x = not (sndBigger (swap x))
// If two elements of the tuple are same, it should give 'false'
let prop_sndBiggerEq a =
sndBigger (a, a) = false
編集:このルールprop_sndBiggerSwap
は常に成立するとは限りません ( kvbによるコメントを参照)。ただし、以下は正しいはずです。
// Reversing values of the tuple negates the result
let prop_sndBiggerSwap a b =
if a <> b then
let x = (a, b)
sndBigger x = not (sndBigger (swap x))
pairs
関数に関しては、 kvbがすでにいくつかの優れたアイデアを投稿しています。さらに、変換されたリストを要素のリストに戻すと、元のリストが返されることを確認できます (入力リストが奇数の場合を処理する必要があります -pairs
この場合に関数が何をすべきかによって異なります)。
let prop_pairsEq (x:_ list) =
if (x.Length%2 = 0) then
x |> pairs |> List.collect (fun (a, b) -> [a; b]) = x
else true
についてsplitOn
は、同様のことをテストできます - 返されたすべてのリストを連結すると、元のリストが得られるはずです (これは分割動作を検証するものではありませんが、最初から始めるのは良いことです - 少なくとも、どの要素も失われます)。
let prop_splitOnEq f x =
x |> splitOn f |> List.concat = x
ただし、 FsCheckがこれを処理できるかどうかはわかりません(!)。これは、プロパティが関数を引数として取るためです (そのため、「ランダムな関数」を生成する必要があります)。これが機能しない場合は、いくつかの手書きの function を使用して、より具体的なプロパティをいくつか提供する必要がありますf
。次に、( kvbf
が示唆するように) 分割されたリスト内のすべての隣接するペアに対して true を返すチェックを実装することは、実際にはそれほど難しくありません。
let prop_splitOnAdjacentTrue f x =
x |> splitOn f
|> List.forall (fun l ->
l |> Seq.pairwise
|> Seq.forall (fun (a, b) -> f a b))
おそらく最後に確認できる唯一のことは、あるリストの最後の要素と次のリストの最初の要素を指定するとf
返されることです。false
以下は完全ではありませんが、進むべき道を示しています。
let prop_splitOnOtherFalse f x =
x |> splitOn f
|> Seq.pairwise
|> Seq.forall (fun (a, b) -> lastElement a = firstElement b)
最後のサンプルは、返される結果のリストの一部として関数が空のリストを返すことができるかどうかを確認する必要があることも示していますsplitOn
(その場合、最初/最後の要素が見つからないため)。