Foldable
是一个超类Traversable
,类似于Functor
超类的Applicative
和Monad
.
类似的情况下Monad
,它可以基本上实现fmap
为
liftM :: Monad m => (a->b) -> m a -> m b
liftM f q = return . f =<< q
Run Code Online (Sandbox Code Playgroud)
我们也可以效仿foldMap
的
foldLiftT :: (Traversable t, Monoid m) => (a -> m) -> t a -> m
foldLiftT f = fst . traverse (f >>> \x -> (x,x))
-- or: . sequenceA . fmap (f >>> \x -> (x, x))
Run Code Online (Sandbox Code Playgroud)
使用Monoid m …
我正在查看文档Data.Traversable
并发现fmapDefault
- https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base/Data-Traversable.html#g:3
fmapDefault :: Traversable t => (a -> b) -> t a -> t b
Run Code Online (Sandbox Code Playgroud)
文件说明 -
如果定义了遍历,则此函数可用作Functor实例中fmap的值.
所以可能它可以用于派生fmap
一个Traversable
实例.然而,Traversable
有Functor
一个超类.
class (Functor t, Foldable t) => Traversable t where
...
Run Code Online (Sandbox Code Playgroud)
因此,如果不先定义Traversable
实例,就无法定义Functor
实例!无论你有什么Traversable
,你都可以访问fmap
,这相当于(也许更有效)fmapDefault
.
那么人们会在哪里使用fmapDefault
,而不是更熟悉fmap
?
该vector-0.1
包具有非常高效的Stream
实现(Data.Vector.Stream
):
data Step s a = Yield a s
| Skip s
| Done
-- | The type of fusible streams
data Stream a = forall s. Stream (s -> Step s a) s Size
Run Code Online (Sandbox Code Playgroud)
后来的版本将其vector
扩展为monadic版本Data.Vector.Fusion.Stream.Monadic
,但为了简单起见,让我们使用旧的,非monadic版本.
Stream
很自然地是Functor
和的一个例子Foldable
:
instance Foldable Stream where
foldMap f s = foldl' (\a b -> a <> (f b)) mempty s
Run Code Online (Sandbox Code Playgroud)
作为一个流,它也应该是一个实例Traversable
,不应该吗?至少乍一看它看起来很简单.我们需要一个
sequenceA :: Applicative f => Stream (f …
Run Code Online (Sandbox Code Playgroud) 我记得在某处读到过这样的类型不能是Traversable
:
data Bar a = Bar a deriving(Show)
instance Functor Bar where
fmap f (Bar x) = Bar (f x)
instance Foldable Bar where
foldMap f (Bar x) = f x <> f x
Run Code Online (Sandbox Code Playgroud)
我记得的一点解释是,为了foldMap = foldMapDefault
保持,Traversable
实例必须多次访问其元素,这是合法实例无法做到的。但是,我不记得为什么合法实例不能这样做。考虑这个:
instance Traversable Bar where
sequenceA (Bar x) = Bar <$ x <*> x
Run Code Online (Sandbox Code Playgroud)
乍一看还不错。这样做有什么违法?
我经常使用下面的函数转换Option[Try[_]]
为Try[Option[_]]
但感觉不对.可以用更惯用的方式表达这样的功能吗?
def swap[T](optTry: Option[Try[T]]): Try[Option[T]] = {
optTry match {
case Some(Success(t)) => Success(Some(t))
case Some(Failure(e)) => Failure(e)
case None => Success(None)
}
}
Run Code Online (Sandbox Code Playgroud)
说我有两个值:
val v1: Int = ???
val v2: Option[Int] = ???
Run Code Online (Sandbox Code Playgroud)
我想op
对这些值进行操作(可能会失败)并将其传递给f
下面的函数.
def op(x: Int): Try[String]
def f(x: String, y: Option[String]): Unit
Run Code Online (Sandbox Code Playgroud)
我通常用于理解可读性:
for {
opedV1 <- op(v1)
opedV2 <- swap(v2.map(op))
} f(opedV1, opedV2)
Run Code Online (Sandbox Code Playgroud)
PS.我想避免像scalaz这样沉重的东西.
我试图在https://namc.in/2018-02-05-foldables-traversals的帮助下了解Traversable 。
作者在某处提到了以下句子:
对应用上下文而言,可遍历是针对Monoid值的可折叠。
他试图澄清什么?
我之间没有联系Foldable to Monoid
。
请提供一个例子。
尽管标题充满了行话,但我认为这个问题并不复杂。
这里有两个重要的 Functor 组合子。Flip
等同于 haskell 函数,flip
但对类型进行操作
newtype Flip p a b
= Flip
{ unFlip :: p b a
}
Run Code Online (Sandbox Code Playgroud)
和Join
相当于对类型在W组合子,它需要一个bifunctor和沿其两个参数产生算符
newtype Join p a
= W
{ unW :: p a a
}
Run Code Online (Sandbox Code Playgroud)
现在Foldable
可以制作以下实例:
instance
( forall a . Foldable (p a)
, forall a . Foldable (Flip p a)
)
=> Foldable (Join p) where
foldr g x (W xs) = foldr g (foldr g x xs) (Flip …
Run Code Online (Sandbox Code Playgroud) AFunList
是 Twan van Laarhoven 在这篇博文中发明的一种数据类型。Bartosz Milewski 给出的一个小变化如下所示:
data FunList a b t = Done t
| More a (FunList a b (b -> t))
Run Code Online (Sandbox Code Playgroud)
关于这种数据类型的一个有趣的事实是,如果我们稍微调整一下类型参数,我们会得到一个Profunctor
:
data FunList t b a
= Done t
| More a (FunList (b -> t) b a)
mapResult :: (a -> b) -> FunList a x y -> FunList b x y
mapResult f (Done x) = Done $ f x
mapResult f (More a r) = …
Run Code Online (Sandbox Code Playgroud) 我需要一个执行此操作的函数:
>>> func (+1) [1,2,3]
[[2,2,3],[2,3,3],[2,3,4]]
Run Code Online (Sandbox Code Playgroud)
我的实际案例更复杂,但这个例子显示了问题的要点.主要的区别在于,实际上使用索引是不可行的.本List
应该是一个Traversable
或Foldable
.
编辑:这应该是功能的签名:
func :: Traversable t => (a -> a) -> t a -> [t a]
Run Code Online (Sandbox Code Playgroud)
更接近我真正想要的是相同的签名,traverse
但无法弄清楚我必须使用的功能,以获得所需的结果.
func :: (Traversable t, Applicative f) :: (a -> f a) -> t a -> f (t a)
Run Code Online (Sandbox Code Playgroud) Base 提供ZipList,它只是[]
where <*>
is basedzip
而不是笛卡尔积的包装器。这不是默认设置,因为它与Monad []
实例不一致,但有些人发现它更直观,并且这两种行为在不同的上下文中都很有用。
Edward Kmett 提供Distributive,Traversable
. 一个 Traversable 可以被映射/推送/分发到任何 Applicative Functor 中;可以从任何 Functor 中提取/分解一个 Distributive。(由于我没有拆包的原因,distribute
不需要外层是适用的。)
长度索引列表是 Distributive,并且按您期望的方式工作。具体来说,他们的 Applicative 实例基于zip
,就像ZipList
! 这表明ZipList
也可能是Distributive
,这将是有用的。
文档的Distributive
注意事项必须是任何实例的两件事:
(->) x
对于某些人来说,它 [必须] 同构x
。”
Int ->
。ZipList
。这够好吗?今天下午我花了几个小时试图写作instance Distributive ZipList where distributive = ...
,但无法让它发挥作用。对于 …
traversable ×10
haskell ×9
applicative ×4
foldable ×2
containers ×1
fold ×1
functor ×1
monoids ×1
optional ×1
scala ×1
stream ×1
typeclass ×1