可遍历数据常量ab =常数a通过Quickchecks,但行为有趣

The*_*Cat 3 haskell traversable

haskell书要我实现可遍历的实例

newtype Constant a b = Constant { getConstant :: a }
Run Code Online (Sandbox Code Playgroud)

包括所有必要的超类.下面的代码通过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)
Run Code Online (Sandbox Code Playgroud)

当我尝试使用这样的可遍历实例时:

traverse (\x -> [x + 1]) $ Constant 5 
Run Code Online (Sandbox Code Playgroud)

我没有得到Constant [5]我希望的,而是

traverse (\x -> [x + 1]) $ Constant 5
  :: (Num b, Num a) => [Constant a b]
Run Code Online (Sandbox Code Playgroud)

这是什么意思?我做错了什么吗?

Lui*_*las 5

当我尝试使用这样的可遍历实例时:

traverse (\x -> [x + 1]) $ Constant 5 
Run Code Online (Sandbox Code Playgroud)

我不知道Constant [5]我希望[...]

你不会得到的Constant [5].让我们写下以下类型traverse:

traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
Run Code Online (Sandbox Code Playgroud)

...并将其与您的实例化对齐:

                  -- 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)
Run Code Online (Sandbox Code Playgroud)

所以我们有:

t = Constant b
f = []
x = Num a => a
y = NUm b => b
Run Code Online (Sandbox Code Playgroud)

请注意,traverse意味着类型t在参数和结果中是相同的.因为你Constant 5 :: Num a => Constant a b用作参数,这意味着你永远不会有Constant [5] :: Num a => Constant [a] b结果,因为Constant a /= Constant [a].

  • @TheUnfunCat:您的实现看起来是正确的.您可以尝试欣赏这一点的一个练习是:如何为"常量"编写不同的"Traversable"实例?(提示:这是一个技巧问题!)无论如何,你的例子应该评估为值[[Constant 5]`; 你应该能够对结果进行模式匹配来验证.这就是"常量"仿函数的要点 - 它是`Functor` /`Applicative` /`Traversable`的极限情况,只是忽略了你在它上面映射的函数. (3认同)