lue-bird / elm-partial-or-complete / PartialOrComplete

We there, yet?


type PartialOrComplete partial complete
    = Partial partial
    | Complete complete

Either we're done and have a Complete result, or we just have incomplete → Partial information.

Check the readme for use-cases

observe

value : PartialOrComplete value value -> value

Treat a Partial result the same as if it was Complete

[ Partial 3, Complete 10 ] |> List.map PartialOrComplete.value
--> [ 3, 10 ]

Often used after a ...UntilComplete.foldUpFrom:

import Linear exposing (Direction(..))
import List.Linear
import Set exposing (Set)

whileValidMove : List Movement -> Set ValidMove
whileValidMove movementRay =
    movementRay
        |> List.Linear.foldUntilCompleteFrom Set.empty
            Up
            (\movement ->
                case movement |> toValidMove of
                    Nothing ->
                        Complete

                    Just validMove ->
                        \soFar -> soFar |> Set.insert validMove |> Partial
            )
        -- succeed even if we've reached the end of the board
        |> PartialOrComplete.value

For more control over how to recover from a Partial case, use a case..of or PartialOrComplete.completeElseOnPartial

completeElseOnPartial : (partial -> complete) -> PartialOrComplete partial complete -> complete

Recover the case where the PartialOrComplete is Partial to return a complete value.

import Linear exposing (Direction(..))
import List.Linear

listTakeFromLast : Int -> (List element -> List element)
listTakeFromLast lengthToTake list =
    list
        |> List.Linear.foldUntilCompleteFrom []
            Down
            (\element takenSoFar ->
                if takenSoFar.length >= lengthToTake then
                    takenSoFar |> Complete

                else
                    { length = takenSoFar.length + 1
                    , list = element :: takenSoFar
                    }
                        |> Partial
            )
        -- succeed even if we've taken less then the maximum amount of elements
        |> PartialOrComplete.completeElseOnPartial .list

Note: PartialOrComplete.completeElseOnPartial identity can be simplified to PartialOrComplete.value

isComplete : PartialOrComplete partial_ complete_ -> Basics.Bool

Conveniently check whether a PartialOrComplete is Complete.

Prefer case..of except for situations like

import Linear exposing (Direction(..))
import List.Linear

listMember : element -> (List element -> Bool)
listMember needle list =
    list
        |> List.Linear.foldUntilCompleteFrom ()
            Up
            (\element () ->
                if element == needle then
                    Complete ()

                else
                    Partial ()
            )
        |> PartialOrComplete.isComplete

alter

onPartialMapFlat : (partial -> PartialOrComplete partialMapped complete) -> PartialOrComplete partial complete -> PartialOrComplete partialMapped complete

In case the PartialOrComplete is Partial, do another step, arriving at another PartialOrComplete state.

This is like an "andThen" from the Partial case.

recurse

recurseUntilComplete : (partial -> PartialOrComplete partial complete) -> partial -> complete

Create a tail-recursive function of one argument

pow : Int -> Int -> Int
pow base exponent =
    { result = 1, exponent = abs exponent }
        |> PartialOrComplete.recurseUntilComplete
            (\state ->
                case state.exponent of
                    0 ->
                        Complete state.result

                    exponentAtLeast1 ->
                        Partial
                            { exponent = exponentAtLeast1 - 1
                            , result = state.result * base
                            }
            )

transform

Maybe

completeOnJust : Maybe complete -> PartialOrComplete () complete

Partial () on Nothing, Complete with the value on Just

import Linear exposing (Direction(..))
import List.Linear

[ Nothing, Nothing, Just 55, Nothing ]
    |> List.Linear.foldUntilCompleteFrom ()
        Up
        (\element () -> element |> PartialOrComplete.completeOnJust)
    |> PartialOrComplete.justOnComplete
--> Just 55

justOnComplete : PartialOrComplete partial_ complete -> Maybe complete

Nothing on Partial, Just the complete value on Complete.

import Linear exposing (Direction(..))
import List.Linear

[ Nothing, Nothing, Just 55, Nothing ]
    |> List.Linear.foldUntilCompleteFrom ()
        Up
        (\element () -> element |> PartialOrComplete.completeOnJust)
    |> PartialOrComplete.justOnComplete
--> Just 55

Result

completeOnOk : Result partial complete -> PartialOrComplete partial complete

Partial with the error on Err, Complete with the value on Ok

import Linear exposing (Direction(..))
import List.Linear

[ Err "a", Err "b", Ok 55, Err "d" ]
    |> List.Linear.foldUntilCompleteFrom "empty list"
        Up
        (\element _ -> element |> PartialOrComplete.completeOnOk)
    |> PartialOrComplete.okOnComplete
--> Ok 55

okOnComplete : PartialOrComplete partial complete -> Result partial complete

Err with the value on Partial, Ok with the value on Complete.

import Linear exposing (Direction(..))
import List.Linear

[ Err "a", Err "b", Ok 55, Err "d" ]
    |> List.Linear.foldUntilCompleteFrom "empty list"
        Up
        (\element _ -> element |> PartialOrComplete.completeOnOk)
    |> PartialOrComplete.okOnComplete
--> Ok 55