如何在不使用List的情况下编写reverseT?

时间:2018-08-12 21:19:35

标签: haskell reverse foldable representable

我需要不使用reverseT的{​​{1}}替代方案。 显然,这段代码是不正确的,但是证明了我追求的想法:

toList

有人知道我可以用什么来代替reverseF :: (Foldable f, Representable f, Num (Rep f)) => f a -> f a reverseF f = tabulate $ \ix -> index f $ last - ix where last = length f - 1 -- Incorrect; length -> ? ,以便在构建length时获得tabulate提供的最后一个索引元素吗?

2 个答案:

答案 0 :(得分:3)

Representable通常不支持reverse,因为无限固定形状的结构可以表示但不可逆,例如。 G。流:

{-# language DeriveFunctor, TypeFamilies #-}

import Data.Distributive
import Data.Functor.Rep

data Stream a = Cons {hd :: a, tl :: Stream a} deriving Functor

instance Distributive Stream where
  distribute fa = Cons (hd <$> fa) (distribute (tl <$> fa))

data Nat = Z | S Nat

instance Representable Stream where
  type Rep Stream = Nat
  tabulate f      = Cons (f Z) (tabulate (f . S))
  index as Z      = hd as
  index as (S n)  = index (tl as) n

对于一般逆转,您需要像Conal的答案中那样有限的Rep,但是我认为单独要求Traversable是可以接受的,并且可能比indextabulate更有效在大多数情况下。您可以使用State应用程序进行反向操作:

import Control.Monad.State.Strict

reverseT :: Traversable t => t a -> t a
reverseT ta =
  evalState (traverse (\_ -> gets head <* modify tail) ta)
            (foldl (flip (:)) [] ta)

答案 1 :(得分:1)

您可以假设并使用Bounded (Rep f)Enum (Rep f),即用Rep fInt转换为toEnum,将索引更改IntInt上使用minBoundmaxBound的{​​{1}}对应项(或假设Rep f),最后从fromEnum minBound == 0返回到{{1 }}和Int