Hi all,
imagine the following types:
type Node
= Node String (List Feature)
type Feature
= Main (List Node)
| Custom String (List Node)
| Text (List Node)
| None
I’m working on an API that allows users to build models with these types. However, I have, amongst others, the following requirement:
A node must not contain a Feature variant more than once. The exception is the Custom
variant, where there can be 0…n, however, each Custom Feature
must have a unique identifier (the first argument of type String
of the Custom
constructor).
To achieve that, I expose an API that let’s users add Node
s to the specific Feature
.
-- exposed
underMain : Node -> Node -> Node
underMain (Node idParent features) child =
Node idParent (addToMainFeature child features)
-- local
addToMainFeature : Node -> List Feature -> List Feature
addToMainFeature child features =
let
(mainChildren, otherFeatures) =
-- collects all children already under the Feature in question (Main) and puts them together with the new ones
List.foldl
(\feature (mChildren, featuresOther) ->
case feature of
Main children ->
(mChildren ++ children, featuresOther)
_ ->
(mChildren, feature :: featuresOther)
)
([child], [])
features
in
Main mainChildren :: otherFeatures
My implementation idea is to use foldl
to collect all children that already exist under a certain Feature
(e.g. the Main
feature) prepend a new Main
feature with all these children at the end. Neither the order of Feature
s nor of Node
s matters at that point.
My specific questions are:
- Is there a easier / better way to satisfy my requirement
- I’d have to copy the
addToXXXFeature
function for theText
feature, and only changecase of
inside the anonymous function to match against theText
constructor. Can this be unified somehow? I’m thinking of aaddToFeature : Feature -> Node -> List Feature -> List Feature
function where the first parameter is theFeature
to put the new node under. However, I don’t understand how I could pattern match the passedFeature
variant to the onefoldl
is processing…?