如何为((->) 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
答案 0 :(得分:6)
通常不存在unwrap
这样的事情,将f
视为列表仿函数[]
unwrap
应该为[_, _, _]
返回什么,或者更好的是空列表[]
?与Maybe
类似,假设h
为const 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
不是。