首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >一般来说,对于可折叠的函数器,有没有等价物呢?

一般来说,对于可折叠的函数器,有没有等价物呢?
EN

Stack Overflow用户
提问于 2018-06-10 23:27:19
回答 4查看 286关注 0票数 5

我只想使用函数式代数来表达以下Haskell代码(即,不依赖于任何特定的容器类型,如List):

代码语言:javascript
复制
ys = zipWith (+) (head xs : repeat 0)
                 (tail xs ++ [y])

在我看来,应该有一种方法来做到这一点,只依赖于Foldable (或者,也许,Traversable),但我看不到它。

我在想:

  1. 对于可折叠/可遍历的函数器是否有first和rest的一般概念?
  2. 是否有一种公认的惯用方法,仅使用函数器代数来移动可折叠/可遍历函数器的内容?(请注意,上面的计算可能用英语描述为“从右侧移入一个值,并将落在左侧的值加回到新的第一个值中。”)
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-06-11 00:06:37

您问题的第一部分(将结构的第一个值与一件事结合起来,其余部分保持不变)可以用Traversable以一种直接的方式完成。我们将使用State,使用我们想要应用的函数启动它,并立即将其修改为id

代码语言:javascript
复制
onlyOnHead :: Traversable t => (a -> a) -> t a -> t a
onlyOnHead f xs = evalState (traverse go xs) f where
    go x = do
        fCurrent <- get
        put id
        return (fCurrent x)

您可以使用类似的方法旋转元素:我们将旋转一个列表,并将其填充到我们的State中作为从中绘制元素的对象。

代码语言:javascript
复制
rotate :: Traversable t => t a -> t a
rotate xs = evalState (traverse go xs) (rotateList (toList xs)) where
    rotateList [] = []
    rotateList vs = tail vs ++ [head vs]

    go _ = do
        v:vs <- get
        put vs
        return v
票数 4
EN

Stack Overflow用户

发布于 2018-06-10 23:42:06

您可以使用Foldable中的FirstLast monoids找到Data.Monoid的第一个或最后一个元素。

代码语言:javascript
复制
foldMap (Last . Just)  :: Foldable t => t a -> Last a
foldMap (First . Just) :: Foldable t => t a -> First a

所有的Foldable都可以转换为一个列表,因此,因为您可以找到列表的头部和尾部,所以您可以对任何Foldable执行此操作。

代码语言:javascript
复制
toList = foldr (:) [] :: Foldable t => t a -> [a]

也就是说,尾部将有一个列表类型,而不是Foldable的类型(除非它也是一个列表)。这归根结底是因为并不是所有的Foldable都可以实现uncons。例如:

data Pair a = Pair a a

这是Foldable,但是您不能使用Pair表示Pair的尾部。

票数 6
EN

Stack Overflow用户

发布于 2018-06-12 05:48:41

要旋转,你不需要任何难看的部分函数。这个奇怪的Applicative将会完成这项工作。

代码语言:javascript
复制
data Foo a t where
  Cons :: (a -> q -> t) -> a -> Foo a q -> Foo a t
  Nil :: t -> Foo a t

instance Functor (Foo a) where
  fmap f (Cons g x xs) = Cons (\p q -> f (g p q)) x xs
  fmap f (Nil q) = Nil (f q)

instance Applicative (Foo a) where
  pure = Nil
  liftA2 f (Nil t) ys = f t <$> ys
  liftA2 f (Cons g x xs) ys = Cons (\a (q,b) -> f (g a q) b) x (liftA2 (,) xs ys)

您可以旋转Foo

代码语言:javascript
复制
rot :: Foo a t -> Foo a t
rot n@(Nil _) = n
rot (Cons g0 a0 as0) = go g0 a0 as0
  where
    go :: (a -> q -> t) -> a -> Foo a q -> Foo a t
    go g a n@(Nil _) = Cons g a n
    go g a (Cons h y ys) = Cons g y (go h a ys)

然后运行一次以获得结果:

代码语言:javascript
复制
runFoo :: Foo a t -> t
runFoo (Nil t) = t
runFoo (Cons g x xs) = g x (runFoo xs)

把这一切放在一起,

代码语言:javascript
复制
rotate :: Traversable t => t a -> t a
rotate = runFoo . rot . traverse (\a -> Cons const a (Nil ()))

然后是rotate [1..10] = [2..10] ++ [1]

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50785210

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档