2015-11-11 3 views
3

У меня есть тип и экземпляр SemiGroup. Я хочу написать метод quickCheck, чтобы убедиться в его правильности. Как создать произвольный экземпляр этого типа?Haskell Произвольный экземпляр типа более высокого порядка

newtype Combine a b = 
    Combine { unCombine :: a -> b } 

instance Semigroup b => Semigroup (Combine a b) where 
    x <> y = Combine $ \n -> unCombine x n <> unCombine y n 

instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a b) where 
    arbitrary = do 
    a <- Q.arbitrary 
    return $ Combine (\n -> Sum(n+1)) a 

ответ

4

Минимальное исправление, чтобы включить FlexibleInstances и написать:

instance (Q.Arbitrary a, Num a) => Q.Arbitrary (Combine a (Sum a)) where 
    arbitrary = do 
    a <- Q.arbitrary :: Q.Gen() 
    return $ Combine (\n -> Sum(n+1)) 

Однако, это немного неудовлетворительное: я замечаю, что a полностью неиспользованный (отсюда следует вручную с учетом типа подписи !), а распределение по функциям является скучным, так как оно возвращает функцию (+1) (вплоть до обертывания нового типа) с вероятностью 1. (Возможно, вы хотели return $ Combine (\n -> Sum (n+a))? Но даже тогда класс функций, которые вы можете создать таким образом, немного я не уверен, что вы на самом деле имели в виду, и я не буду потратьте долгие спекуляции.)

Если вы хотите сделать это правильно, вы должны создать случайный выход для каждого входа. Это очень удобно с universe пакета:

import Data.Universe 
import Data.Universe.Instances.Reverse 
instance (Ord a, Finite a, Q.Arbitrary b) => Q.Arbitrary (Combine a b) where 
    arbitrary = Combine <$> sequenceA (const Q.arbitrary) 

Как побочный эффект, это не требует каких-либо расширений. Тем не менее, вы должны быть осторожны, чтобы выбирать типы ввода с небольшими доменами - Combine Bool (Sum Int) должно быть хорошо или даже Combine Word8 (Sum Word8), но если вы попробуете испытать свойство на таком типе, как Combine Int (Sum Int), вам будет жаль!

+0

Это похоже на то, что я хочу. Я новичок в haskell и пытаюсь выяснить, как добавить эти зависимости в мой единственный файл, используя стек. Без файла yaml или cabal. Когда я это выясню, я буду отмечать ваш ответ и возвышение, когда я докажу, что это работает. Спасибо за подробный ответ. – mac10688

+0

@ mac10688 Если вы не используете файл стека или файл cabal, вам необходимо установить пакет с 'cabal install'. Чтобы иметь явные зависимости, вам необходимо использовать файл стека или файл кэба. –

+0

@DavidYoung Я смог использовать стек ghci --resolver nightly-2015-11-10 - пакуя юниверса QuickCheck. Теперь я обрабатываю некоторые компиляционные ошибки. – mac10688

Смежные вопросы