Portability | non-portable |
---|---|

Stability | experimental |

Maintainer | Edward Kmett <ekmett@gmail.com> |

Safe Haskell | None |

This module provides a `Zipper`

with fairly strong type checking guarantees.

The code here is inspired by Brandon Simmons' `zippo`

package, but uses
a slightly different approach to represent the `Zipper`

that makes the whole thing
look like his breadcrumb trail, and can move side-to-side through traversals.

Some examples types:

`Top`

`:>`

a- represents a trivial
`Zipper`

with its focus at the root. `Top`

`:>`

`Tree`

a`:>`

a- represents a zipper that starts with a
`Tree`

and descends in a single step to values of type`a`

. `Top`

`:>`

`Tree`

a`:>`

`Tree`

a`:>`

`Tree`

a- represents a
`Zipper`

into a`Tree`

with an intermediate bookmarked`Tree`

, focusing in yet another`Tree`

.

Since individual levels of a zipper are managed by an arbitrary `Traversal`

,
you can move left and right through the `Traversal`

selecting neighboring elements.

`>>>`

("Jelly","world")`zipper ("hello","world") & down _1 & fromWithin traverse & focus .~ 'J' & farthest right & focus .~ 'y' & rezip`

This is particularly powerful when compiled with `plate`

,
`uniplate`

or `biplate`

for walking down into
self-similar children in syntax trees and other structures.

- data Top
- data p :> a
- zipper :: a -> Top :> a
- focus :: SimpleIndexedLens (Tape (h :> a)) (h :> a) a
- up :: ((a :> b) :> c) -> a :> b
- down :: SimpleLensLike (Context c c) b c -> (a :> b) -> (a :> b) :> c
- within :: SimpleLensLike (Bazaar c c) b c -> (a :> b) -> Maybe ((a :> b) :> c)
- left :: (a :> b) -> Maybe (a :> b)
- right :: (a :> b) -> Maybe (a :> b)
- tug :: (a -> Maybe a) -> a -> a
- tugs :: (a -> Maybe a) -> Int -> a -> a
- jerks :: (a -> Maybe a) -> Int -> a -> Maybe a
- farthest :: (a -> Maybe a) -> a -> a
- tooth :: (a :> b) -> Int
- teeth :: (a :> b) -> Int
- jerkTo :: Int -> (a :> b) -> Maybe (a :> b)
- tugTo :: Int -> (a :> b) -> a :> b
- rezip :: Zipper h a => (h :> a) -> Zipped h a
- type family Zipped h a
- class Zipper h a
- data Tape k
- saveTape :: (a :> b) -> Tape (a :> b)
- restoreTape :: Tape (h :> a) -> Zipped h a -> Maybe (h :> a)
- restoreNearTape :: Tape (h :> a) -> Zipped h a -> Maybe (h :> a)
- fromWithin :: SimpleLensLike (Bazaar c c) b c -> (a :> b) -> (a :> b) :> c
- unsafelyRestoreTape :: Tape (h :> a) -> Zipped h a -> h :> a

# Zippers

This is the type of a `Zipper`

. It visually resembes a 'breadcrumb trail' as
used in website navigation. Each breadcrumb in the trail represents a level you
can move up to.

This type operator associates to the left, so you can use a type like

`Top`

`:>`

(`String`

,`Double`

)`:>`

`String`

`:>`

`Char`

to represent a zipper from `(`

down to `String`

,`Double`

)`Char`

that has an intermediate
crumb for the `String`

containing the `Char`

.

## Focusing

## Horizontal Movement

## Lateral Movement

## Movement Combinators

tug :: (a -> Maybe a) -> a -> aSource

This allows you to safely 'tug left' or 'tug right' on a `zipper`

.

The more general signature allows its use in other circumstances, however.

tugs :: (a -> Maybe a) -> Int -> a -> aSource

This allows you to safely 'tug left' or 'tug right' on a `zipper`

, moving multiple steps in a given direction,
stopping at the last place you couldn't move from.

jerks :: (a -> Maybe a) -> Int -> a -> Maybe aSource

This allows for you to repeatedly pull a `zipper`

in a given direction, failing if it falls of the end.

## Absolute Positioning

## Closing the zipper

rezip :: Zipper h a => (h :> a) -> Zipped h aSource

Close something back up that you opened as a `zipper`

.

This represents the type a zipper will have when it is fully `Zipped`

back up.

## Recording

saveTape :: (a :> b) -> Tape (a :> b)Source

Save the current path as as a `Tape`

we can play back later.

restoreTape :: Tape (h :> a) -> Zipped h a -> Maybe (h :> a)Source

Restore ourselves to a previously recorded position precisely.

If the position does not exist, then fail.

restoreNearTape :: Tape (h :> a) -> Zipped h a -> Maybe (h :> a)Source

Restore ourselves to a location near our previously recorded position.

When moving left to right through a `Traversal`

, if this will clamp at each level to the range `0 <= k < teeth`

,
so the only failures will occur when one of the sequence of downward traversals find no targets.

## Unsafe Movement

fromWithin :: SimpleLensLike (Bazaar c c) b c -> (a :> b) -> (a :> b) :> cSource

Unsafely step down into a `Traversal`

that is *assumed* to be non-empty.

If this invariant is not met then this will usually result in an error!

`fromWithin`

::`Simple`

`Traversal`

b c -> (a :> b) -> a :> b :> c`fromWithin`

::`Simple`

`Lens`

b c -> (a :> b) -> a :> b :> c`fromWithin`

::`Simple`

`Iso`

b c -> (a :> b) -> a :> b :> c

You can reason about this function as if the definition was:

`fromWithin`

l ≡`fromJust`

`.`

`within`

l

but it is lazier in such a way that if this invariant is violated, some code can still succeed if it is lazy enough in the use of the focused value.

unsafelyRestoreTape :: Tape (h :> a) -> Zipped h a -> h :> aSource

Restore ourselves to a previously recorded position.

This *assumes* that nothing has been done in the meantime to affect the existence of anything on the entire path.

Motions left or right are clamped, but all traversals included on the `Tape`

are assumed to be non-empty.

Violate these assumptions at your own risk!