2017-10-17 20 views
4

Ninety-Nine Haskell Problems單元測試IO INT和類似在Haskell

Question 23提取從列表中隨機選擇的元件的給定數目。

這是部分解決方案。爲了簡單起見,這段代碼只是從列表中選擇一個元素。

import System.Random (randomRIO) 

randItem :: [a] -> IO a 
randItem xs = do 
    i <- randomRIO (0,length xs - 1) 
    return $ xs !! i 

所以randItem [1..10]將通過10

返回對應於(但不等於)的IO Int一些詮釋從1到目前爲止,一切都很好。但是,我可以爲我的randItem函數編寫什麼樣的測試?什麼關係 - 如果有的話 - 我可以確認輸入和輸出之間的關係嗎?

我可以使用與上述函數相同的邏輯來生成m Bool,但我無法弄清楚如何測試m Bool。謝謝。

+1

我想你想定義'randItem':: SomeClass m => [a] - > m a',其中'SomeClass'提供了一個函數來代替'randomRIO'。然後,如果你爲'IO'定義了一個適當的'SomeClass'實例,你可以使用'randItem'[1..10] :: IO'獲得一個隨機值,或者'randItem'[1..10]: :SomeTestMonad',它提供了另一種確定性的用於測試的'randomRIO'替代實現。 – chepner

+1

'randItem :: [a] - > IO a'然後就是'randItem''到'IO'類型的一個特殊化。 – chepner

+0

@chepner爲什麼要定義一個新的類型類? 「RandomGen」有什麼問題? –

回答

4

有幾件事你可以做。如果您使用QuickCheck,則可以編寫以下屬性:

  • 返回列表的長度應該等於輸入長度。
  • 返回列表中的所有元素應該是候選者列表的元素。

除此之外,哈斯克爾的隨機庫的美是(與其他大多數Haskell代碼一樣)它是確定性的。如果不是基於randomRIO的實施,您可以將其基於randomRrandomRs。這將使您能夠將一些已知的RandomGen值傳遞給某些確定性單元測試用例(不是QuickCheck)。這些可以作爲迴歸測試。

+0

我錯過了QuickCheck的東西。仍然無法看到如何完成elem(IO Int)[Int]。這是我試過quickCheck((\ list - > elem(randItem list)list):: [Int] - > Bool)Haskell非常新。我會執行你的第二個建議(randomR)。謝謝。 – Shay

+1

@Shay嘗試使用類型'RandomGen g => g - > Int - > [a] - > [a]'來編寫一個函數。我在接下來的幾個小時內遠離我的開發環境,所以建議可能包含一兩個錯字(我正在寫這個在我的手機上),但希望它能給你一個關於如何繼續的想法。 –

+2

「返回列表中的所有元素都應該是候選者列表的元素。」 - 我認爲這是自由定理的結果。如果是這樣,那麼不需要測試! :-) – chi