jjant / elm-comonad-zipper / Zipper

This package provides an implementation of a List Zipper as well as its corresponding comonadic interface, namely, the functions extract, duplicate and extend.

These are useful to perform transformations which depend on the neighborhood of the elements, see extend for one such example.

You can find more complete examples here.


type Zipper a
    = Zipper (List a) a (List a)

A Zipper a is a nonempty list with a focused element.

append : List a -> Zipper a -> Zipper a

Add elements at the end of the Zipper.

import Zipper exposing (Zipper(..))

Zipper.append [ 5, 4 ] (Zipper [ 0 ] 1 [ 2, 3 ]) == Zipper [ 0 ] 1 [ 2, 3, 5, 4 ]

prepend : List a -> Zipper a -> Zipper a

Add elements at the beginning of the Zipper.

import Zipper exposing (Zipper(..))

Zipper.prepend [ -1, -2 ] (Zipper [ 0 ] 1 [ 2, 3 ]) == Zipper [ -1, -2, 0 ] 1 [ 2, 3 ]

toList : Zipper a -> List a

Transforms a Zipper into a regular list.

import Zipper exposing (Zipper(..))

Zipper.toList (Zipper [0] 1 [2,3,4]) == [0,1,2,3,4]

Extracting values

prev : Zipper a -> List a

Returns the elements before the focused element.

  import Zipper exposing (Zipper(..))

  Zipper.prev (Zipper [0] 1 [2,3,4]) == [0]

extract : Zipper a -> a

Returns the focused element.

import Zipper exposing (Zipper(..))

Zipper.extract (Zipper [0] 1 [2,3,4]) == 1

next : Zipper a -> List a

Returns the elements after the focused element.

  import Zipper exposing (Zipper(..))

  Zipper.next (Zipper [0] 1 [2,3,4]) == [2,3,4]

Navigating

leftMay : Zipper a -> Maybe (Zipper a)

Attempts to select the element to the left of the focus, returns Nothing if there are no previous elements.

  import Zipper exposing (Zipper(..))

  Zipper.leftMay (Zipper [] 1 [2,3,4]) == Nothing

  Zipper.leftMay (Zipper [1] 2 [3,4]) == Just (Zipper [] 1 [2, 3, 4])

rightMay : Zipper a -> Maybe (Zipper a)

Attempts to select the element to the right of the focus, returns Nothing if there are no next elements.

import Zipper exposing (Zipper(..))

Zipper.rightMay (Zipper [0] 1 []) == Nothing

Zipper.rightMay (Zipper [1] 2 [3,4]) == Just (Zipper [1, 2] 3 [4])

left : Zipper a -> Zipper a

Attempts to select the element to the left of the focus. Returns the Zipper unchanged if there are no previous elements.

  import Zipper exposing (Zipper(..))

  Zipper.left (Zipper [] 1 [2,3,4]) == Zipper [] 1 [2,3,4]

  Zipper.left (Zipper [1] 2 [3,4]) == Zipper [] 1 [2, 3, 4]

right : Zipper a -> Zipper a

Attempts to select the element to the right of the focus. Returns the Zipper unchanged if there are no next elements.

import Zipper exposing (Zipper(..))

Zipper.right (Zipper [0] 1 []) == Zipper [0] 1 []

Zipper.right (Zipper [1] 2 [3,4]) == Zipper [1, 2] 3 [4]

Transforming elements

map : (a -> b) -> Zipper a -> Zipper b

Apply a function to every element in the Zipper.

import Zipper exposing (Zipper(..))

Zipper.map (\x -> 2 * x) (Zipper [2, 0, 5] 1 [2]) == Zipper [4, 0, 10] 2 [4]

duplicate : Zipper a -> Zipper (Zipper a)

Returns a Zipper in which every element is a Zipper list.

import Zipper exposing (Zipper(..))

duplicate (Zipper [0] 1 [2]) == Zipper [Zipper [] 0 [1,2]] (Zipper [0] 1 [2]) [Zipper [0, 1] 2 []]

extend : (Zipper a -> b) -> Zipper a -> Zipper b

Map elements in the Zipper, having access to the elements before and after it.

import Zipper exposing (Zipper(..))

maxSoFar (Zipper prev curr _) = List.foldr Basics.max curr prev

Zipper.extend maxSoFar (Zipper [2, 1, 3, 4, 5] 1 [2]) == Zipper [2, 2, 3, 4, 5] 5 [5]