listzipper icon indicating copy to clipboard operation
listzipper copied to clipboard

[Feature] map with different functions for selected and not selected elements

Open andys8 opened this issue 5 years ago • 3 comments

Hi, there,

great library! I'm missing a mapping function where one can provide two different functions for mapping elements, depending on the element being selected or not.

My use case is a view that renders the selected element different. It won't work with mixing mapCurrent with mapBefore/After (without an intermediate step), because they're a -> a. map is from a -> b but the information if it's current is not provided.

Examples from other libraries

mapCS : (a -> b) -> (a -> b) -> Pivot a -> Pivot b

https://package.elm-lang.org/packages/yotamDvir/elm-pivot/latest/Pivot#mapCS

selectedMap : (Position -> SelectList a -> b) -> SelectList a -> List b

https://package.elm-lang.org/packages/miyamoen/select-list/latest/SelectList#selectedMap

Implementation

Here are three sample implementations for the feature. The api, name and implementation of the function can be discussed :)

mapBoth1 : { mapCurrent : a -> b, mapElse : a -> b } -> Zipper a -> Zipper b
mapBoth1 { mapCurrent, mapElse } zipper =
    let
        mapFn a =
            if a == Zipper.current zipper then
                mapCurrent a

            else
                mapElse a
    in
    Zipper.map mapFn zipper
mapBoth2 : { mapCurrent : a -> b, mapElse : a -> b } -> Zipper a -> Zipper b
mapBoth2 { mapCurrent, mapElse } zipper =
    Zipper.from
        (zipper |> Zipper.before |> List.map mapElse)
        (zipper |> Zipper.current |> mapCurrent)
        (zipper |> Zipper.after |> List.map mapElse)
mapBoth3 : (Bool -> a -> b) -> Zipper a -> Zipper b
mapBoth3 f zipper =
    Zipper.map (\a -> f (a == Zipper.current zipper) a) zipper

andys8 avatar Jul 18 '19 12:07 andys8

Hi, @andys8,

Sorry for not getting back to you sooner. I like your proposal. Would you prefer an object with mapCurrent and mapElse over two functions (that, admittedly, can be ambiguous as the type signature is the same)? In any case, I think I prefer the function signature of mapBoth1 and mapBoth2 over that of mapBoth3.

All function names (mapBoth, mapCS and selectMap) are fine with me (although I wouldn't be able to predict what the function does from neither of those names)

With regards to the implementation: I think that destructuring the Zipper would be easiest. In that case you don't have to check each element to see if it is the focus of the zipper (you know that already).

Would you be willing to make a pull request for this?

wernerdegroot avatar Oct 09 '19 17:10 wernerdegroot

I realize that this is basically a :+1: comment, so apologies if it's unwelcome, but I also just ran into an occasion where I would have liked a function like the ones proposed here!

rjdellecese avatar Feb 19 '20 20:02 rjdellecese

I'm working on a different project and I once again found that I would have loved to have this function. Should you find the time to merge https://github.com/wernerdegroot/listzipper/pull/29 @wernerdegroot, I would definitely be grateful for it!

rjdellecese avatar Jul 23 '20 22:07 rjdellecese