Отслеживается для данных Constant a b = Constant a проходит Quickchecks, но действует смешно
Книга Haskell хочет, чтобы я реализовал проходимый экземпляр для
newtype Constant a b = Constant { getConstant :: a }
включая все необходимые суперклассы. Код ниже проходит Quickcheck/Checkers
, но действует смешно
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
newtype Constant a b = Constant { getConstant :: a }
instance Functor (Constant a) where
fmap f (Constant a) = Constant a
instance Foldable (Constant a) where
foldr f z (Constant x) = z
instance Traversable (Constant a) where
traverse f (Constant a) = pure $ Constant a
type TI = []
main = do
let trigger = undefined :: TI (Int, Int, [Int])
quickBatch (traversable trigger)
Когда я пытаюсь использовать проходимый экземпляр, вот так:
traverse (\x -> [x + 1]) $ Constant 5
Я не понимаю Constant [5]
на что я надеялся, но скорее
traverse (\x -> [x + 1]) $ Constant 5
:: (Num b, Num a) => [Constant a b]
Что это значит? Я сделал что-то не так?
1 ответ
Когда я пытаюсь использовать проходимый экземпляр, вот так:
traverse (\x -> [x + 1]) $ Constant 5
Я не понимаю
Constant [5]
на который я надеялся [...]
Вы не собираетесь получить Constant [5]
, Давайте напишем тип для traverse
:
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
... и выровняйте это с вашей реализацией этого:
-- I've substituted `x` for `a` and `y` for `b` in the
-- first type, because otherwise my head hurts.
(x -> f y) -> t x -> f (t y)
(Num a, Num b) => (a -> [] a) -> (Constant b) a -> [] ((Constant b) a)
Итак, мы имеем:
t = Constant b
f = []
x = Num a => a
y = NUm b => b
Обратите внимание, что тип для traverse
подразумевает, что t
будет одинаковым в аргументе и результате. Так как вы используете Constant 5 :: Num a => Constant a b
в качестве аргумента, это означает, что вы никогда не можете иметь Constant [5] :: Num a => Constant [a] b
в результате, потому что Constant a /= Constant [a]
,