Generate lenses for variant values
VariantLensBuild
of named erlandsona/elm-accessors
which with
{ build =
VariantLens.GenerateUsed.accessors
{ valuesRepresent = VariantLens.GenerateUsed.tupleNest }
, name = VariantLens.GenerateUsed.prismNameVariant
, generationModuleIsVariantModuleDotSuffix = "On"
}and
module Data exposing (Data(..))
type Data a b c d
= Some a b c d
| Nonegenerates
module Data.On exposing (some)
import Accessors exposing (makeOneToN_)
import Data exposing (Data(..))
{-| Accessor lens for the variant `Data.Some` of the `type Data`.
-}
some :
Relation ( a, ( b, ( c, d ) ) ) reachable wrap
-> Relation (Data a b c d) reachable (Maybe wrap)
some =
makeOneToN_
"Data.Some"
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothing
)
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
other
)VariantLensBuild
of unnamed bChiquet/elm-accessors
which with
{ build =
VariantLens.GenerateUsed.accessorsBChiquet
{ valuesRepresent = VariantLens.GenerateUsed.tupleNest }
, name = VariantLens.GenerateUsed.prismNameVariant
, generationModuleIsVariantModuleDotSuffix = "On"
}and
module Data exposing (Data(..))
type Data a b c d
= Some a b c d
| Nonegenerates
module Data.On exposing (some)
import Accessors exposing (Lens, Relation, makeOneToN_)
import Data exposing (Data(..))
{-| Accessor lens for the variant `Data.Some` of the `type Data`.
-}
some :
Relation ( a, ( b, ( c, d ) ) ) reachable wrap
-> Relation (Data a b c d) reachable (Maybe wrap)
some =
makeOneToN
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothing
)
(\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
other
)Build a different documentation:
accessorsDocumentedCustom info =
accessors
{ valuesRepresent = valuesRecord }
info
|> documented
(emptyDocComment
|> markdown
("variant `" ++ info.variantName ++ "`: Accessor lens for the values.")
)Build a different type annotation:
import Hand exposing (Hand(..))
import Stack
accessorsAnnotatedLens : VariantLensBuild
accessorsAnnotatedLens info =
accessors
{ valuesRepresent = valuesRecord }
info
|> annotated
(typed "Option"
[ CodeGen.typed info.typeName
(info.typeParameters |> List.map CodeGen.typeVar)
, case variantValues |> Stack.fromList of
Empty _ ->
CodeGen.unitAnn
Filled stacked ->
Filled stacked
|> Stack.reverse
|> Stack.fold (\value soFar -> CodeGen.tupleAnn [ value, soFar ])
, CodeGen.typeVar "reachable"
, CodeGen.typeVar "wrap"
]
)
|> importsAdd
[ impostStmt [ "Accessors" ]
Nothing
([ "Option" |> typeOrAliasExpose ] |> exposingExplicit |> Just)
]Make sure to importsAdd.
Supply additional imports required for generating the declaration.
accessorsAnnotatedLens : VariantLensBuild
accessorsAnnotatedLens info =
accessors info
|> annotated (typed "Option" [ ... ])
|> importsAdd
[ impostStmt [ "Accessors" ]
Nothing
([ "Option" |> typeOrAliasExpose ] |> exposingExplicit |> Just)
]Helpers for values of a given variant among >= 2.
for
type Data a b c d
= Some a b c d
| Nonewith
variantAmongMultiple tupleNestaccess\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter |> Just
_ ->
Nothingalter\valuesAlter variantType ->
case variantType of
Some value0 value1 value2 value3 ->
let
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3
other ->
otherHelpers for values of a given only variant.
for
type Id attachment
= Id (List Int) attachmentaccess\(Id value0 value1) -> ( value0, value1 )alter\valuesAlter (Id value0 value1) ->
let
( alteredValue0, alteredValue1 ) =
( value0, value1 ) |> valuesAlter
in
Id alteredValue0 alteredValue1Representation of values as one whole, for example
valuesRecord: { value0 = ..., value1 = ..., value2 = ... }tupleNest: ( ..., ( ..., ... ) )Toop.T3 ... ... ...Helpers for a given variant to use with a custom implementation or variantOnly/variantAmongMultiple.
for
type Data a b c d
= Some a b c d
| NonetypeInOne( a, ( b, ( c, d ) ) )inOne "value"( value0, ( value1, ( value2, value3 ) ) )patternInOne "value"( value0, ( value1, ( value2, value3 ) ) )alterlet
( alteredValue0, ( alteredValue1, ( alteredValue2, alteredValue3 ) ) ) =
( value0, ( value1, ( value2, value3 ) ) ) |> valuesAlter
in
Some alteredValue0 alteredValue1 alteredValue2 alteredValue3Helpers for a given variant to use with a custom implementation or variantOnly/variantAmongMultiple.
for
type Data a b c d
= Some a b c d
| Noneaccess{ value0 = value0, value1 = value1, value2 = value2, value3 = value3 }alterlet
altered =
{ value0 = value0, value1 = value1, value2 = value2, value3 = value3 }
|> valuesAlter
in
Some altered.value0 altered.value1 altered.value2 altered.value3typeValues{ value0 = a, value1 = b, value2 = c, value3 = d }Pattern on a given variant to use with a custom implementation.
for
type Data a b c d
= Some a b c d
| Nonegenerates
Some value0 value1 value2 value3How to derive lens name <=> variant name.
Out of the box, there are
You can also create a custom VariantLensNameConfig:
import Parser
{ build = \{ variantName } -> variantName ++ "Variant"
, parser =
Parser.map (\variantName -> { variantName = variantName })
(Parser.loop ""
(\beforeSuffixFoFar ->
Parser.oneOf
[ Parser.token "Variant"
|. Parser.end
|> Parser.map (\() -> Parser.Done beforeSuffixFoFar)
, Parser.chompIf (\_ -> True)
|> Parser.getChompedString
|> Parser.map
(\stillNotSuffix ->
Parser.Loop (beforeSuffixFoFar ++ stillNotSuffix)
)
]
)
)
}It's not half as daunting as it looks. If you feel motivated 👀 ↓
elm/parser packageMini tip: testing is always a good idea for Parsers
Don't worry about the case of the results.
They will be automatically be corrected when passed to rule.
Handle lens names in the format on<Variant>.
Check out VariantLensNameConfig for all naming options.
import Parser
import VariantLens.GenerateUsed
"success"
|> Parser.run VariantLens.GenerateUsed.prismNameOnVariant.parser
--> { variantName = "Success" }
{ variantName = "Success" }
|> VariantLens.GenerateUsed.prismOnVariant.build
--> "success"Handle lens names in the format on<Variant>.
Check out VariantLensNameConfig for all naming options.
import Parser
import VariantLens.GenerateUsed
"onSuccess"
|> Parser.run VariantLens.GenerateUsed.prismNameOnVariant.parser
--> { variantName = "Success" }
{ variantName = "Success" }
|> VariantLens.GenerateUsed.prismOnVariant.build
--> "onSuccess"
Generate prisms for variant
types that are called from your code but aren't already defined in a dedicatedmodule...config.. How to generate, where to generate:
build :aVariantLensBuildfunction likeaccessorsaccessorsBChiquetname :a way to handle variant lens names likeprismNameOnVariantprismNameVariantgenerationModuleIsVariantModuleDotSuffix :a.Suffixto derive generationmodulenames from variantmodulenamesThere's no configuration to automatically
import Variant.Module.Generation as Variant.Modulebecauseimportaliases can't contain.example
module Variant.Module.On exposing (some)example:
module Variant.Module.X exposing (onSome)use it
... when you're using
elm-accessorsto mitigate boilerplate related to updating potentially deeply nested data.don't use it
... when you consider lenses the less readable/intuitive/simple/explicit alternative.