有许多仿函数看起来像容器(列表,序列,地图等),还有许多仿函数没有(状态变换器,Foldable
,解析器等)。我还没有看到任何看起来像容器的非平凡Traversable
或{{1}}个实例(至少如果你稍微眯一下)。有存在吗?如果没有,我很想更好地了解他们为什么不能这样做。
答案 0 :(得分:20)
对于某些Traversable f
Normal s
与s :: Nat -> *
同构
data Normal (s :: Nat -> *) (x :: *) where -- Normal is Girard's terminology
(:-) :: s n -> Vec n x -> Normal s x
data Nat = Zero | Suc Nat
data Vec (n :: Nat) (x :: *) where
Nil :: Vec Zero n
(:::) :: x -> Vec n x -> Vec (Suc n) x
但是在Haskell中实现iso并不是一件容易的事(但是完全依赖类型值得一试)。在道德上,你选择的s
是
data {- not really -} ShapeSize (f :: * -> *) (n :: Nat) where
Sized :: pi (xs :: f ()) -> ShapeSize f (length xs)
和iso的两个方向分离并重新组合形状和内容。事物的形状仅由fmap (const ())
给出,关键点是f x
形状的长度是f x
本身的长度。
向量可以在访问 - 每次 - 从左到右的意义上遍历。通过保持形状(因此大小)和遍历元素向量,可以精确地遍历法线。可遍历的是有限多个元素位置以线性顺序排列:与普通仿函数的同构精确地以线性顺序暴露元素。相应地,每个Traversable
结构都是一个(有限的)容器:它们有一组形状 - 大小和相应的位置概念,由自然数的初始段给出,严格小于大小。
Foldable
事物也是有形的,它们将事物保持在一个顺序中(有一个明智的toList
),但它们不能保证是Functor
s,所以他们不要有一个如此清晰的形状的概念。从这个意义上讲(由我的同事Abbott,Altenkirch和Ghani定义的“容器”意义),他们不一定承认形状和位置的特征,因此不是容器。如果你很幸运,他们中的一些人可能是一些容器。确实存在Foldable
以允许处理像Set
这样的结构,其内部结构是秘密的,并且当然取决于对遍历操作不一定遵守的元素的排序信息。究竟是什么构成一个表现良好的Foldable
是一个有争议的问题,但是:我不会对该库设计选择的实用好处进行狡辩,但我希望有一个更清晰的规范。
答案 1 :(得分:10)
好吧,在universe的帮助下,有可能在有限状态空间上为状态变换器编写Foldable
和Traversable
个实例。这个想法大致类似于函数的Foldable
和Traversable
个实例:在Foldable
的任何地方运行函数,并为Traversable
创建一个查找表。因此:
import Control.Monad.State
import Data.Map
import Data.Universe
-- e.g. `m ~ Identity` satisfies these constraints
instance (Finite s, Foldable m, Monad m) => Foldable (StateT s m) where
foldMap f m = mconcat [foldMap f (evalStateT m s) | s <- universeF]
fromTable :: (Finite s, Ord s) => [m (a, s)] -> StateT s m a
fromTable vs = StateT (fromList (zip universeF vs) !)
float :: (Traversable m, Applicative f) => m (f a, s) -> f (m (a, s))
float = traverse (\(fa, s) -> fmap (\a -> (a, s)) fa)
instance (Finite s, Ord s, Traversable m, Monad m) => Traversable (StateT s m) where
sequenceA m = fromTable <$> traverse (float . runStateT m) universeF
我不确定这是否合理。如果确实如此,我想我很乐意将其添加到包装中;你觉得怎么样?
答案 2 :(得分:4)
我不认为它实际上是可折叠的或可穿越的,但是MonadRandom是一个可以像无限列表一样工作的例子,但它看起来不像容器,而不是任何其他可折叠的东西。从概念上讲,它是一个随机变量。