Let’s take this piece by piece. Put an _what
(underscore what) after the last =
, like so
setComplexText value textValues = _what
-- Found hole: _what : ComplexText
And you’ll see that error, meaning the expression at _what
must have type ComplexText
. (what
can be anything, the only important thing is to start with a _
. In this example, _what
is the hole, and ComplexText
is the goal type.
Ok, there’s only one way to make a ComplexText
. Moreover, we’ll have to pull out the textValues
from the argument. So let’s do both of those:
setComplexText value (ComplexText {textValues})=
ComplexText with textValues = _tv
-- Found hole: _tv : [TextValue]
The function you’re looking for is map
. Let’s use that:
ComplexText with textValues = map _f textValues
-- Found hole: _f : TextValue -> TextValue
Well, we could write \tv -> tv
and that would type, but you want to change the TextValue
s. So let’s just elaborate the lambda:
ComplexText with textValues = map (\tv -> _otv) textValues
-- Found hole: _otv : TextValue
-- • Relevant bindings include
-- tv : TextValue
-- (bound at .../Main.daml:74:39)
-- textValues : [TextValue]
-- (bound at ...:73:36)
-- value : Text
You’ll note that when you introduce a variable, the “hole” error includes information about the type of that variable, which is really useful when you’re drilling down into complex structures, and not something that top-level variable declarations can really help you with.
You really want to have a different result based on which case tv : TextValue
is in, so you can split it out into its cases:
ComplexText with textValues = map (\tv -> case tv of
OneText {..} -> _one
TwoTexts {..} -> _two
ThreeTexts {..} -> _three) textValues
Each of _one
, _two
, _three
is a separate error, each with different bindings; for example, the _two
error tells you that text1
and text2
are available.
There are more language features that can shrink this code once you have this basic form working, but I would leave those for another post
However, I would definitely suggest structuring TextValue
differently. Since text1
occurs in every case, it would be better to have a record type with two fields: text1
, and a second field of a variant type that contains nothing, text2
, or text2
and text3
.
Another alternative might be to use the “algebraic” form: your type is exactly as expressive as (Text, Optional (Text, Optional Text))
, but the latter form has the benefit that various functions already exist for it. There’s a tradeoff here regarding the flexibility of your domain-specific TextValue
form, but it is a tradeoff worth evaluating rather than dismissing.