Merging record recursively with Optional nested values


#1

Hello,

To update the optional record attribute of a Kubernetes resources template, is there a way to use the /\ operator?

For example, how could this be implemented:

let Kubernetes = ./package.dhall

in        Kubernetes.DeploymentSpec::{
          , template = Kubernetes.PodTemplateSpec::{
            , metadata = Kubernetes.ObjectMeta::{ name = "test" }
            , spec = Some Kubernetes.PodSpec::{=}
            }
          }
      /\  { template =
              { spec = Some Kubernetes.PodSpec::{
                , serviceAccount = Some "builder"
                }
              }
          }
    : Kubernetes.DeploymentSpec.Type

This is failing on a field collision of spec. It seems like I have to use a custom function to traverse the Optional type, but perhaps there is a more efficient way to do that? I was wondering if the /\, or a new one, could be used to automatically unwrap the optional value (e.g. merge record when both operand are Some).


#2

I think, even if the PodSpec in the spec field wasn’t wrapped in Some, /\ wouldn’t work: You’d still get field conflicts, for example for the serviceAccount field.

So I believe you’ll have to use // until the with operator for nested overrides from https://github.com/dhall-lang/dhall-lang/issues/754 is implemented. This should work:

let Kubernetes = ./package.dhall

let x =
      Kubernetes.DeploymentSpec::{
      , template = Kubernetes.PodTemplateSpec::{
        , metadata = Kubernetes.ObjectMeta::{ name = "test" }
        , spec = Some Kubernetes.PodSpec::{=}
        }
      }

in      x
      ⫽ { template =
              x.template
            ⫽ { spec = Some Kubernetes.PodSpec::{
                , serviceAccount = Some "builder"
                }
              }
        }
    : Kubernetes.DeploymentSpec.Type

With with it should look like this:

let Kubernetes = ./package.dhall

let x =
      Kubernetes.DeploymentSpec::{
      , template = Kubernetes.PodTemplateSpec::{
        , metadata = Kubernetes.ObjectMeta::{ name = "test" }
        , spec = Some Kubernetes.PodSpec::{=}
        }
      }

in    x with { template.spec.serviceAccount = Some "builder" }
    : Kubernetes.DeploymentSpec.Type

#3

Oh wow, the with syntax sounds amazing, thank you for the pointer!