2017-09-20 54 views
1

如何为((->) a)编写Traversable实例?如何在函数中编写一个Traversable实例,在Haskell中?

我想我能做到这一点,如果一般能解开一个适用函子

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 [email protected](pure x) = x 

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

Parse error in pattern: pure 
+0

首先你需要创建一个'Foldable'的实例。 – 4castle

+1

'pure'是一个函数,而不是数据构造函数。与函数值的构造函数最接近的是lambda表达式:'\ x - > x + 1 :: Num a =>( - > a)a'。你认为你可以从这个函数中提取什么类型的'Num a => a'的值? – chepner

回答

6

通常没有unwrap这样的东西,可以考虑f作为列表函数[]unwrap应该返回什么对于[_, _, _]或更好的空列表[]?类似的事情Maybe,假设hconst Nothing,你会得到Nothing。但是,当您尝试将unwrapNothing设置为值a时,您的思路就会失败。你可以注意到,尝试应用pure(重新包装的结果在仿函数),意味着你希望得到的结果总是JustMaybe函子,非空的[]

没有为Traversable希望渺茫实例为读者函子((->) 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 

假设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) 
1

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

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

unwrap (Just x) = x 

是有效的,而

unwrap (pure x) = x 

不是。