Created
September 4, 2019 17:51
-
-
Save BrianHicks/d8469943d714dfc3fb39a17d397c9b84 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Slice exposing | |
( Slice, slice | |
, Multiple, Position(..), before, after, getList | |
, Single, first, last, get, map | |
) | |
{-| Bisect a `Todos` in whatever way. | |
# initializing a slice | |
@docs Slice, slice | |
# working with multiple matches | |
@docs Multiple, Position, before, after, getList | |
# working with single matches | |
@docs Single, first, last, get, map | |
-} | |
import Filter exposing (Filter) | |
import List.Extra -- a private implementation, not elm-community's | |
import Todo exposing (Todo) | |
import Todos exposing (Todos) | |
type Slice quantity | |
= Leaf quantity | |
| Before (Slice quantity) (Maybe Todo) (List Todo) | |
| After (List Todo) (Maybe Todo) (Slice quantity) | |
{-| Having Multiple means that there are many possible remaining options in the | |
slice. You can get a list of them, but you can't query for an individual yet. | |
-} | |
type Multiple | |
= Multiple (List Todo) | |
type Position | |
= First | |
| Last | |
slice : Todos -> Slice Multiple | |
slice todos = | |
Leaf (Multiple (Todos.toList todos)) | |
before : Position -> Filter -> Slice Multiple -> Slice Multiple | |
before position filter query_ = | |
case query_ of | |
Leaf (Multiple todos) -> | |
let | |
( before_, pivot, after_ ) = | |
split position filter todos | |
in | |
Before (Leaf (Multiple before_)) pivot after_ | |
Before next pivot after_ -> | |
Before (before position filter next) pivot after_ | |
After before_ pivot next -> | |
After before_ pivot (before position filter next) | |
after : Position -> Filter -> Slice Multiple -> Slice Multiple | |
after position filter query_ = | |
case query_ of | |
Leaf (Multiple todos) -> | |
let | |
( before_, pivot, after_ ) = | |
split position filter todos | |
in | |
After before_ pivot (Leaf (Multiple after_)) | |
Before next pivot after_ -> | |
Before (after position filter next) pivot after_ | |
After before_ pivot next -> | |
After before_ pivot (after position filter next) | |
getList : Slice Multiple -> List Todo | |
getList query_ = | |
case query_ of | |
Before next _ _ -> | |
getList next | |
After _ _ next -> | |
getList next | |
Leaf (Multiple todos) -> | |
todos | |
{-| Having Single means that there is one remaining possible option in the | |
slice. You can get or map the individual, but you can't go back to having | |
multiple matches. | |
-} | |
type Single | |
= Single (List Todo) (Maybe Todo) (List Todo) | |
first : Filter -> Slice Multiple -> Slice Single | |
first filter query_ = | |
case query_ of | |
Leaf (Multiple todos) -> | |
let | |
( before_, after_ ) = | |
List.Extra.splitBefore (Filter.matcher filter) todos | |
in | |
Leaf (Single before_ (List.head after_) (Maybe.withDefault [] (List.tail after_))) | |
Before next pivot after_ -> | |
Before (first filter next) pivot after_ | |
After before_ pivot next -> | |
After before_ pivot (first filter next) | |
last : Filter -> Slice Multiple -> Slice Single | |
last filter query_ = | |
case query_ of | |
Leaf (Multiple todos) -> | |
let | |
( retfa, erofeb ) = | |
List.Extra.splitBefore (Filter.matcher filter) (List.reverse todos) | |
in | |
Leaf <| | |
Single | |
(erofeb | |
|> List.tail | |
|> Maybe.withDefault [] | |
|> List.reverse | |
) | |
(List.head erofeb) | |
(List.reverse retfa) | |
Before next pivot after_ -> | |
Before (last filter next) pivot after_ | |
After before_ pivot next -> | |
After before_ pivot (last filter next) | |
get : Slice Single -> Maybe Todo | |
get query_ = | |
case query_ of | |
Before next _ _ -> | |
get next | |
After _ _ next -> | |
get next | |
Leaf (Single _ next _) -> | |
next | |
map : (Todo -> Todo) -> Slice Single -> Maybe ( Todos, Todo ) | |
map mapper query_ = | |
mapHelp mapper query_ | |
|> Maybe.map (Tuple.mapFirst Todos.fromList) | |
mapHelp : (Todo -> Todo) -> Slice Single -> Maybe ( List Todo, Todo ) | |
mapHelp mapper query_ = | |
case query_ of | |
Before next pivot after_ -> | |
let | |
middle = | |
pivot | |
|> Maybe.map List.singleton | |
|> Maybe.withDefault [] | |
in | |
Maybe.map (Tuple.mapFirst (\todos -> todos ++ middle ++ after_)) | |
(mapHelp mapper next) | |
After before_ pivot next -> | |
let | |
middle = | |
pivot | |
|> Maybe.map List.singleton | |
|> Maybe.withDefault [] | |
in | |
Maybe.map (Tuple.mapFirst (\todos -> before_ ++ middle ++ todos)) | |
(mapHelp mapper next) | |
Leaf (Single before_ Nothing after_) -> | |
Nothing | |
Leaf (Single before_ (Just this) after_) -> | |
let | |
mapped = | |
mapper this | |
in | |
Just | |
( before_ ++ [ mapped ] ++ after_ | |
, mapped | |
) | |
split : Position -> Filter -> List Todo -> ( List Todo, Maybe Todo, List Todo ) | |
split position filter todos = | |
let | |
splitter = | |
-- my List.Extra.splitBefore is like elm-community/list-extra's splitWhen but does not return a Maybe | |
List.Extra.splitBefore (Filter.matcher filter) | |
in | |
case position of | |
First -> | |
let | |
( before_, after_ ) = | |
splitter todos | |
in | |
( before_ | |
, List.head after_ | |
, Maybe.withDefault [] (List.tail after_) | |
) | |
Last -> | |
let | |
( retfa, erofeb ) = | |
splitter (List.reverse todos) | |
in | |
( erofeb | |
|> List.tail | |
|> Maybe.withDefault [] | |
|> List.reverse | |
, List.head erofeb | |
, List.reverse retfa | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment