A Setter is an optic that can see into a structure and set or modify its focus.

It is a generalization of map. A structure S that has a focus A to which we can apply a function (A) -> B to S and get T. For example, S == List<Int> to which we apply (Int) -> String and we get T == List<String>.

  • List<Int>.map(f: (Int) -> String): List<String>
  • PSetter#modify(s: List<Int>, f: (Int) -> String): List<String>

You can get a Setter for any existing map.

To create your own Setter, you need to define how to apply (A) -> B to S.

A Setter<Player, Int> can set and modify the value of Player. So we need to define how to apply a function (Int) -> Int to Player.


Unlike a regular set function, a Setter composes. Similar to a Lens, we can compose Setters to focus into nested structures and set or modify a value.

Setter can be composed with all optics but Getter and Fold. It results in the following optics:

  Iso Lens Prism Optional Getter Setter Fold Traversal
Setter Setter Setter Setter Setter X Setter X Setter

Polymorphic setter

When dealing with polymorphic types, we can also have polymorphic setters that allow us to morph the type of the focus. Previously, when we used a Setter<List<Int>, Int>, it was able to morph the Int values in the constructed type List<Int>. With a PSetter<List<Int>, List<String>, Int, String>, we can morph an Int value to a String value and thus also morph the type from List<Int> to List<String>.


Arrow provides SetterLaws in the form of test cases for internal verification of lawful instances and third party apps creating their own setters.

Do you like Arrow?

Arrow Org