kudzu-forest/elm-zipper-pull/2.0.1

NOTE: the latest version is 5.0.0

ZipperPull

INTERFACE TYPE

type alias Interface stock model output =
{ focusLeft : model -> model
, focusRight : model -> model
, focusLeftEnd : model -> model
, focusRightEnd : model -> model
, isLeftEnd : model -> Bool
, isRightEnd : model -> Bool
, indexFromLeft : model -> Int
, indexFromRight : model -> Int
, map : (stock -> stock) -> model -> model
, toLeftHeadList : model -> List stock
, toRightHeadList : model -> List stock
, foldl : (stock -> output -> output) -> output -> model -> output
, foldr : (stock -> output -> output) -> output -> model -> output
, mapToLeftHeadList : (stock -> output) -> model -> List output
, mapToRightHeadList : (stock -> output) -> model -> List output
}

A record containing functions for manipulating specified data type as list zipper. The type parameter output should not be specifide.

CREATION

{ getRightList : model -> List a
, getLeftList : model -> List a
, getFocus : model -> a
, setRightList : List a -> model -> model
, setLeftList : List a -> model -> model
, setFocus : a -> model -> model
}
-> Interface a model b

The way you can attach list zipper interface on ordinary record.

type alias Model =
    { title : String
    , readCount : Int
    , previousVolumes : List (String, Int)
    , latterVolumes : List (String, Int)
    }


model : Model
model =
    { title = "Philosopher's Stone"
    , readCount = 3
    , previousVolumes = []
    , latterVolumes =
        [ ("Chamber of Secrets",2)
        , ("Prisoner of Azkaban",2)
        , ("Goblet of Fire",3)
        , ("Order of the Phoenix",2)
        , ("Half-Blood Prince",1)
        , ("Deathly Hallows",1)
        ]
    }


pull : Interface (String, Int) Model output
pull =
    create
        { getRightList = .latterVolumes
        , getLeftList = .previousVolumes
        , getFocus = \m -> (m.title, m.readCount)
        , setRightList = \l m -> {m| latterVolumes = l}
        , setLeftList = \f m -> {m| previousVolumes = f}
        , setFocus = \(t,c) m -> {m| title=t, readCount=c}
        }


model
  |> pull.focusRightEnd
  |> pull.focusLeft
  --> { title = "Half-Blood Prince" , readCount = 1 , previousVolumes = [ ("Order of the Phoenix", 2) , ("Goblet of Fire", 3) , ("Prisoner of Azkaban", 2) , ("Chamber of Secrets", 2) , ("Philosopher's Stone", 3) ] , latterVolumes = [ ("Deathly Hallows", 1) ] }


model |> pull.isLeftEnd --> True


model |> pull.focusRight |> pull.isLeftEnd --> False


model |> pull.isRightEnd --> False


model |> pull.focusRightEnd |> pull.isRightEnd --> True


model
    |> pull.foldl
        (\(title, count) str ->
            str
            ++ "I have read \""
            ++ title
            ++ "\" "
            ++ String.fromInt count
            ++ " times. "
        )
        ""
        --> "I have read \"Philosopher's Stone\" 3 times. " ++ "I have read \"Chamber of Secrets\" 2 times. " ++ "I have read \"Prisoner of Azkaban\" 2 times. " ++ "I have read \"Goblet of Fire\" 3 times. " ++ "I have read \"Order of the Phoenix\" 2 times. " ++ "I have read \"Half-Blood Prince\" 1 times. " ++ "I have read \"Deathly Hallows\" 1 times. "


model
    |> pull.foldr
        (\(_, count) sofar -> sofar + count)
        0
        --> 14


model
    |> pull.indexFromLeft
    --> 0

Too few functions?

The interface does not have updateFocus : (stock -> stock) -> model -> model, insertLeft : stock -> model -> model, getLeftList : model -> List stock etc. This is because these operation can be done simpler way with ordinary record operations. It may be confusing to have more than one way of doing one thing. If you have any inconvinience, please tell me or make a pull request.