如何在Haskell中为函数编写Traversable实例?

时间:2017-09-20 21:43:29

标签: haskell traversable

如何为((->) a)编写 Traversable 实例?

我想我可以做到,如果我可以通常打开 Applicative Functor

instance Traversable ((->) k) where
  -- traverse :: (a -> f b) -> (k -> a) -> f (k -> b)
  -- traverse h t = ?
  -- h                     :: Applicative f => a -> f b
  -- t                     :: k -> a
  -- h . t                 :: k -> f b
  -- unwrap . h . t        :: k -> b
  -- pure $ unwrap . h . t :: f (k -> b)
  traverse h t = pure $ unwrap . h . t

unwrap :: (Functor f, Applicative f) => f a -> a
unwrap y@(pure x) = x

但是,唉,GHC不会让我逃脱:

Parse error in pattern: pure

2 个答案:

答案 0 :(得分:6)

通常不存在unwrap这样的事情,将f视为列表仿函数[] unwrap应该为[_, _, _]返回什么,或者更好的是空列表[]?与Maybe类似,假设hconst Nothing,您可能会获得Nothing。但是,在尝试将unwrap Nothing转换为值a时,您的思路就会失败。您可以注意到,尝试应用pure(将结果重新打包到仿函数中)意味着您希望Just仿函数的结果始终为Maybe[]非{ {1}}等等。

读者仿函数Traversable的{​​{1}}实例几乎没有希望。虽然这不是证明,但在这方面的一个好证据是((->) k)中缺少这样的实例。另外,为了遍历函数并生成最终容器(Prelude[]),您需要将函数Maybe应用于函数的任何可想到的输出,这是很多潜在的值,一般无限多。

h

假设Prelude> traverse (\n -> if n == 42 then Nothing else Just n) [1, 2, 3] Just [1,2,3] Prelude> traverse (\n -> if n == 42 then Nothing else Just n) [1..] Nothing k,因此仿函数为Int,假设您有一个值Int ->,让它为g :: Int -> Int,假设您想要要使用上述函数遍历该值,如果\n -> if n == 42 then 0 else n为任何输入输出Nothing,则遍历将为g,但事实并非如此。遍历不能知道虽然(它无法访问函数的代码),所以它必须尝试所有输出。

如果42是有限的,那么你可以通过制表来遍历一个函数。遍历表后,您可能会产生结果。这可能不是你想要的,但是:

k

答案 1 :(得分:1)

  

但是,唉,GHC不会让我逃脱:

您的错误似乎是您尝试使用函数(pure)作为模式。 Haskell只允许构造函数出现在模式中。所以

unwrap (Just x) = x

有效,而

unwrap (pure x) = x

不是。