Тест QuickCheck случайно зависает

Я новичок в Хаскеле. Я играю с тестами QuickCheck, пытаюсь протестировать простую функцию calculateStrengthSingle (см. источник тестируемого ниже)

# Fighter.hs
module Fighter
( Quantity(Quantity)
, Fighter(TeamPlayer, LoneWolf, Polymorph)
, Strength(Strength)
, calculateStrengthSingle)
where

import System.Random

data Strength = Strength Double

instance Eq Strength where
    Strength s1 == Strength s2 =
        s1 == s2

instance Ord Strength where
    Strength s1 < Strength s2 =
        s1 < s2

data Quantity = Quantity Int deriving (Show)

instance Random Quantity where
    randomR (Quantity lo, Quantity hi) g =
        let rand = randomR (lo, hi) g
            (r, g1) = rand
        in (Quantity r, g1)
    random g =
        let rand = random g
            (r, g1) = rand
        in (Quantity r, g1)

data Fighter = TeamPlayer
             | LoneWolf
             | Polymorph
    deriving (Show)


calculateStrengthSingle :: Quantity -> Fighter -> Strength
calculateStrengthSingle (Quantity number) TeamPlayer =
    Strength(log (fromIntegral number))
calculateStrengthSingle _ _ = Strength 0.0

Тест выглядит так

# TestFighter.hs
import qualified Test.QuickCheck as QuickCheck
import Fighter

prop_StrengthPositive quantity fighter =
    Fighter.calculateStrengthSingle quantity fighter >= Strength 0.0

instance QuickCheck.Arbitrary Fighter.Fighter where
    arbitrary = QuickCheck.oneof([return Fighter.TeamPlayer, return Fighter.LoneWolf, return Fighter.Polymorph])

instance QuickCheck.Arbitrary Fighter.Quantity where
    arbitrary = QuickCheck.choose(Fighter.Quantity 1, Fighter.Quantity 10)

main :: IO()
main = do
    QuickCheck.quickCheck prop_StrengthPositive

Когда я делаю runhaskell TestFighter.hs есть выход (1 test) (номер меняется, иногда это 0 в других случаях это 4) и процессор загружен на 100%. Ничего не происходит в течение минуты или около того. Когда я прерываю программу Ctrl+Cвыплевывает что-то вроде

^C*** Failed! Exception: 'user interrupt' (after 1 test):  
Quantity 2
TeamPlayer

Вопросы:

  1. Где я все испортил?
  2. Как я могу отлаживать случаи бесконечного вычисления, как этот?

2 ответа

Решение

Вы не определили Ord экземпляр для Strength правильно. Вам нужно определить <= и не <,

Только с < определил функцию <= входит в бесконечный цикл, как это определено с точки зрения compare а также compare определяется с точки зрения <=, Минимальное определение должно определять либо compare или же <=,

Вот фиксированный код для Ord пример

instance Ord Strength where
    Strength s1 <= Strength s2 =
        s1 <= s2

Вы можете попробовать запустить тест с -o 1 в качестве параметра, который вызывает тайм-аут после одной секунды. Затем он может отобразить ввод, который вызвал зависание вашей программы. Это не говорит вам точно, где проблема, но это хорошее начало.

РЕДАКТИРОВАТЬ: так я использую тестовый фреймворк с Cabal

test-Suite runTests
   hs-source-dirs:      src, test
   type:                exitcode-stdio-1.0
   main-is:             RunTests.hs
   other-modules:
                       <...>

  build-depends:       base >= 3 && < 5,
                       HUnit,
                       test-framework,
                       test-framework-th,
                       test-framework-hunit,
                       test-framework-quickcheck2,
                       QuickCheck,

Чтобы быть полным в моем описании, я строю, используя:

cabal-dev install --enable-tests
Другие вопросы по тегам