Как написать reverseT без использования List?
Мне нужна альтернатива reverseT
это не использует 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
при создании f
?
2 ответа
Representable
не поддерживается reverse
в общем, потому что бесконечные структуры фиксированной формы представимы, но не обратимы, например, потоки:
{-# 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
Для общего обращения вам нужно конечное Rep
как в ответе Конала, но я думаю, требуя Traversable
само по себе было бы приемлемым и, вероятно, более эффективным, чем index
а также tabulate
в большинстве случаев. Вы можете повернуть вспять, используя 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)
Вы могли бы принять и использовать Bounded (Rep f)
а также Enum (Rep f)
то есть конвертировать Rep f
в Int
с toEnum
изменить индексы на несколько Int
арифметика, которая использует Int
аналоги minBound
а также maxBound
на Rep f
(или предположим, fromEnum minBound == 0
) и, наконец, из Int
вернуться к Rep f
с fromEnum
,