我试图自己实施traverse
和sequenceA
:
以traverse'
方式sequenceA
实施traverse' :: (Functor t, Foldable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse' f x = sequenceA' $ fmap f x
:
sequenceA
但是,我坚持实施sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' x = foldr (\a _ -> fmap helper a) (error "...") x
。
b
我使用error "..."
(b
)的占位符 - 我不确定如何在给定这些类型的情况下创建helper :: (Functor t, Foldable t) => a -> t a
helper x = error "TODO"
。
helper
另外,我使用error
函数来获取此代码以进行类型检查。但是,再一次,这只是一个sequenceA
电话。
请给我一些关于如何一般性地实施breaks
的提示。
答案 0 :(得分:8)
假设:
traverse' :: (Functor t, Foldable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse' a2fb ta = sequenceA' (fmap a2fb ta)
sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' tfa = _
洞的理想用途!我们给所有参数命名(不需要去点免费,让我们的生活变得非常困难)并在定义应该是一个洞。这会产生:
src/Main.hs:8:14: Found hole ‘_’ with type: f (t a) …
我们现在转向一个返回f (t a)
之类的函数。幸运的是,traverse'
确实如此,现在我们可以改进我们的洞:
sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' tfa = traverse _ _
src/Main.hs:8:27: Found hole ‘_’ with type: a0 -> f a …
src/Main.hs:8:29: Found hole ‘_’ with type: t a0 …
第一个看起来很混乱,但我们知道第二个符合t a0
的东西,即tfa
。插头和突突:
sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' tfa = traverse _ tfa
src/Main.hs:8:27: Found hole ‘_’ with type: f a -> f a …
好吧,我们知道带有该签名的函数,那就是id
。所以我们的最终答案是:
traverse' :: (Functor t, Foldable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse' a2fb ta = sequenceA' (fmap a2fb ta)
sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' tfa = traverse id tfa
我们现在可以变得年轻,狂野,无拘无束(-ish):
traverse' :: (Functor t, Foldable t, Applicative f) => (a -> f b) -> t a -> f (t b)
traverse' a2fb = sequenceA' . fmap a2fb
sequenceA' :: (Functor t, Foldable t, Applicative f) => t (f a) -> f (t a)
sequenceA' = traverse id