Олег Киселев показал, как сделать молнию из любой пройденной, используя разграниченные продолжения. Его код Haskell довольно короткий:
module ZipperTraversable where
import qualified Data.Traversable as T
import qualified Data.Map as M
-- In the variant Z a k, a is the current, focused value
-- evaluate (k Nothing) to move forward
-- evaluate (k v) to replace the current value with v and move forward.
data Zipper t a = ZDone (t a)
| Z a (Maybe a -> Zipper t a)
make_zipper :: T.Traversable t => t a -> Zipper t a
make_zipper t = reset $ T.mapM f t >>= return . ZDone
where
f a = shift (\k -> return $ Z a (k . maybe a id))
-- The Cont monad for delimited continuations, implemented here to avoid
-- importing conflicting monad transformer libraries
newtype Cont r a = Cont{runCont :: (a -> r) -> r}
instance Monad (Cont r) where
return x = Cont $ \k -> k x
m >>= f = Cont $ \k -> runCont m (\v -> runCont (f v) k)
-- Two delimited control operators,
-- without answer-type polymorphism or modification
-- These features are not needed for the application at hand
reset :: Cont r r -> r
reset m = runCont m id
shift :: ((a -> r) -> Cont r r) -> Cont r a
shift e = Cont (\k -> reset (e k))
У меня возникли проблемы с попыткой реализовать его в Scala. Я начал использовать пакет продолжения Scala, но даже используя идею Rompf richIterable, обобщенную на @cps [X] вместо @suspendable, невозможно функция, предоставляемая для переключения возврата другого типа, чем функция, предоставленная reset.
Я попытался реализовать продолжение монады после определения Киселева, но Scala затрудняет параметры типа curry, и я не мог понять, как превратить Cont [R] в монаду таким образом, чтобы метод трассировки раскола был счастлив с.
Я начинаю как в Haskell, так и в Scala, и буду очень благодарен за помощь в этом.