module Lazy.Zipper exposing (..) import Lazy exposing (Lazy) import Lazy.List exposing (LazyList, (:::)) type alias Zipper a = { before : LazyList a , focus : Lazy a , after : LazyList a } {- Basic conversion -} fromList : a -> List a -> Zipper a fromList a l = Zipper Lazy.List.empty (pure a) (Lazy.List.fromList l) toList : Zipper a -> List a toList rl = Lazy.List.toList (Lazy.List.reverse rl.before) ++ [Lazy.force rl.focus] ++ Lazy.List.toList rl.after {- Functor like things -} map : (a -> b) -> Zipper a -> Zipper b map f rl = Zipper (Lazy.List.map f rl.before) (Lazy.map f rl.focus) (Lazy.List.map f rl.after) edit : (a -> a) -> Zipper a -> Zipper a edit f rl = Zipper rl.before (Lazy.map f rl.focus) rl.after {- Comonad functions -} extract : Zipper a -> a extract rl = rl.focus |> Lazy.force duplicate : Zipper a -> Zipper (Zipper a) duplicate rl = let lefts = iterate1N (Lazy.List.length rl.before) shiftRight rl rights = iterate1N (Lazy.List.length rl.after) shiftLeft rl in Zipper lefts (pure rl) rights extend : (Zipper a -> b) -> Zipper a -> Zipper b extend f w = map f (duplicate w) (=>>) : Zipper a -> (Zipper a -> b) -> Zipper b (=>>) = flip extend {- Domain functions -} shiftLeft : Zipper a -> Zipper a shiftLeft rl = case Lazy.List.headAndTail rl.after of Just (x, xs) -> Zipper (Lazy.force rl.focus ::: rl.before) (pure x) xs Nothing -> case Lazy.List.headAndTail (Lazy.List.reverse rl.before) of Just (x, xs) -> Zipper (Lazy.List.singleton (Lazy.force rl.focus)) (pure x) xs Nothing -> Zipper nil rl.focus nil shiftRight : Zipper a -> Zipper a shiftRight rl = case Lazy.List.headAndTail rl.before of Just (x, xs) -> Zipper xs (pure x) (Lazy.force rl.focus ::: rl.after) Nothing -> case Lazy.List.headAndTail (Lazy.List.reverse rl.after) of Just (x, xs) -> Zipper xs (pure x) (Lazy.List.singleton (Lazy.force rl.focus)) Nothing -> Zipper nil rl.focus nil {- From here we have private functions -} iterate1N : Int -> (a -> a) -> a -> LazyList a iterate1N n f a = case n of 0 -> nil m -> f a ::: Lazy.List.map f (iterate1N (m - 1) f a) nil = Lazy.List.empty pure x = Lazy.lazy (always x)