Skip to content

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

@njlr

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