Skip to content

Usage question: default value for lens to option? #53

Description

@njlr

Suppose I have a map like this:

type Employee = 
  {
    JobTitle : string
    Salary : int
  }
  with 
    static member Salary_ = 
      (fun x -> x.Salary), (fun v x -> { x with Salary = v })

let employees = 
  Map.empty
  |> Map.add "alice" { JobTitle = "Manager"; Salary = 86 }
  |> Map.add "bob" { JobTitle = "Customer Support"; Salary = 76 }

I want to create an optic for updating the salaries. Something like:

let myLens name = 
  Map.value_ name >-> Employee.Salary_

However, this optic is Lens<Map<string, Employee>, int option>.

Instead, I would like a Lens<Map<string, Employee>, int>, by providing a default int value.

Something like:

// Not real code
let myLens name = 
  Map.value_ name >-> Employee.Salary_ >-> Lens.defaultValue 0

How should I do this?


Here is what I came up with, but I have a feeling this is already built into the library:

let composeOption (b : Lens<'b, 'c>) (a : Lens<'a, 'b option>) : Lens<'a, 'c option> =
  let getA, setA = a
  let getB, setB = b

  let get = (fun x -> getA x |> Option.map getB)
  let set = (fun (v : 'c option) (x : 'a) ->
    match getA x with
    | Some b ->
      match v with
      | Some c -> x |> setA (setB c b |> Some)
      | None -> x
    | None -> x
  )

  get, set

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions