繁体   English   中英

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

[英]How to write a Traversable instance for function, in Haskell?

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

我想我可以做到的, 如果我可以一般地打开一个应用函子

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

但是,a,GHC不会让我逃避这一点:

Parse error in pattern: pure

通常,不存在unwrap ,请考虑将f作为列表函子[] ,对于[_, _, _]还是对空列表[] [_, _, _] unwrap返回什么? Maybe相似,假设hconst Nothing ,您期望得到Nothing 但是,你的思路会失败在试图unwrapNothing成值a 您可能会注意到,尝试应用pure (将结果重新包装在函子中)意味着您期望结果始终为Just for Maybe functor,非空为[]等。

读者函子((->) k) Traversable实例几乎没有希望。 尽管不是证据,但朝着这个方向的充分证据是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

假设kInt ,所以函子为Int -> ,假设您有一个值g :: Int -> Int ,令它为\\n -> if n == 42 then 0 else n ,假设您想遍历那个如果使用上面的函数的值,则遍历为Nothing如果g为任何输入输出42 ,但没有。 尽管遍历无法知道(它无法访问该函数的代码),所以它将不得不尝试所有输出。

如果k是有限的,那么您可以通过列表将其遍历。 遍历表格后,您可能会产生结果。 这可能不是您想要的,但是:

import Data.Char
import Data.Maybe
import Data.Word

instance ( Enum k, Bounded k ) => Foldable ((->) k) where
    foldMap h f = foldMap (h . f) domain

instance ( Enum k, Bounded k, Eq k ) => Traversable ((->) k) where
    traverse h f = fmap (\vs k -> fromJust $ k `lookup` zip domain vs) (traverse (h . f) domain)

domain :: ( Enum k, Bounded k ) => [k]
domain = enumFromTo minBound maxBound

tabulate :: ( Enum k, Bounded k ) => (k -> a) -> [(k, a)]
tabulate f = zip domain (map f domain)

f1 :: Bool -> Int
f1 b = if b then 42 else 666

f2 :: Ordering -> Char
f2 LT = 'l'
f2 EQ = 'e'
f2 GT = 'g'

f3 :: Word8 -> Bool
f3 n = fromIntegral n < 256

f4 :: Word16 -> Bool
f4 n = fromIntegral n < 256

main = do
    print (tabulate f1)
    print (tabulate <$> traverse (\n -> [n, 2*n]) f1)
    putStrLn ""
    print (tabulate f2)
    print (tabulate <$> traverse (\c -> [c, toUpper c]) f2)
    putStrLn ""
    print (tabulate f3)
    print (tabulate <$> traverse (\b -> if b then Just b else Nothing) f3)
    putStrLn ""
    print (tabulate <$> traverse (\b -> if b then Just b else Nothing) f4)

但是,a,GHC不会让我逃避这一点:

看来您的错误是您试图使用一个函数( pure )作为模式。 Haskell仅允许构造函数以模式出现。 所以

unwrap (Just x) = x

有效,而

unwrap (pure x) = x

不是。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM