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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions