我正在尝试使用Data.Traversable遍历haskell中数据结构的所有成员,该文档记录在以下网址中:
http://hackage.haskell.org/package/base-4.6.0.1/docs/Data-Traversable.html http://www.haskell.org/haskellwiki/Foldable_and_Traversable
到目前为止,我已经提出了以下代码,据我所知,错过了Tr.Traversable实例化的正确实现。
import qualified Data.Traversable as Tr
import qualified Data.Foldable as Fl
import Control.Monad
import Control.Applicative
data Test = Test { desc :: String
, value :: Int
}
data Data t = Data { foo :: t
, bar :: t
}
exampleData = Data { foo = Test "Foo" 1
, bar = Test "Bar" 2
}
instance Show Test where
show f = (desc f) ++ ": " ++ (show $ value f)
instance (Show a) => Show (Data a) where
show f = show (foo f)
instance Functor Data where
fmap = Tr.fmapDefault
instance Fl.Foldable Data where
foldMap = Tr.foldMapDefault
instance Tr.Traversable Data where
traverse f = Data f -- Try to show a Test entry inside the Data structure
--
-- traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
--
main = do
putStrLn $ show exampleData
Tr.traverse (putStrLn show) exampleData
我正在尝试打印exampleData中的所有项目,逐个成员并使用show。我是否在正确的轨道上,如何实施可穿越的实例?
答案 0 :(得分:4)
我会使用语言扩展为我派生出来:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFoldable #-}
import qualified Data.Traversable as Tr
import qualified Data.Foldable as Fl
import Control.Monad
import Control.Applicative
data Test = Test { desc :: String
, value :: Int }
data Data t = Data { foo :: t
, bar :: t } deriving (Functor, Tr.Traversable, Fl.Foldable)
exampleData = Data { foo = Test "Foo" 1
, bar = Test "Bar" 2
}
instance Show Test where
show f = (desc f) ++ ": " ++ (show $ value f)
instance (Show a) => Show (Data a) where
show f = show (foo f)
main = do
putStrLn $ show exampleData
Tr.traverse (putStrLn . show) exampleData
> runhaskell test_traversable.hs
Foo: 1
Foo: 1
Bar: 2
()
如果你想知道编译器如何自动实现它,你可以用-ddump-deriv
标志编译它(清理一下):
instance Functor Data where
fmap f (Data foo' bar') = Data (f foo') (f bar')
instance Tr.Traversable Data where
tr.traverse f (Data foo' bar') = Data <$> (f foo') <*> (f bar')
instance Fl.Foldable Data where
Fl.foldr f z (Data foo' bar') = f foo' (f bar' z)
答案 1 :(得分:3)
此处的典型Traversable
实施将是
traverse f (Data foo bar) = Data <$> f foo <*> f bar
答案 2 :(得分:3)
因此,您对traverse
的定义并未与给定的签名统一。
traverse f = Data f -- f :: x implies Data f :: x -> Data x, so this implies
traverse :: x -> x -> Data x
如果Data
是Traversable
的实例,那么我们会将Tr.traverse
专门化为
Tr.traverse :: Applicative f => (a -> f b) -> Data a -> f (Data b)
尝试统一它们会产生问题:
traverse ~ Tr.traverse if and only if
x ~ (a -> f b)
x ~ Data a
Data x ~ f (Data b)
这就是编译器抱怨的原因:
Couldn't match expected type `Data a' with actual type `a -> f b'
In the first argument of `Data', namely `f'
In the expression: Data f
In an equation for `traverse': traverse f = Data f
所以让我们为遍历提供一个有效的定义:
traverse f (Data a a') = Data <$> f a <*> f a'
接下来,您的主要功能出错了。当你的意思是Tr.traverse (putStrLn show) exampleData
时,你写了Tr.traverse (putStrLn . show) exampleData
。
putStrLn
的类型为String -> IO ()
,因此putStrLn show
需要show
才能成为字符串以进行类型检查,但show :: Show a -> a -> String
。
这就是编译器抱怨的原因:
Couldn't match expected type `Test -> IO b0'
with actual type `IO ()'
In the return type of a call of `putStrLn'
Probable cause: `putStrLn' is applied to too many arguments
In the first argument of `Tr.traverse', namely `(putStrLn show)'
In a stmt of a 'do' block: Tr.traverse (putStrLn show) exampleData
Couldn't match type `a0 -> String' with `[Char]'
Expected type: String
Actual type: a0 -> String
In the first argument of `putStrLn', namely `show'
In the first argument of `Tr.traverse', namely `(putStrLn show)'
In a stmt of a 'do' block: Tr.traverse (putStrLn show) exampleData
您想使用.
运算符编写这些函数:
putStrLn . show == \a -> putStrLn (show a)
您也可以使用定义为print
的{{1}}。