gcanti / monocle-ts

Functional optics: a (partial) porting of Scala monocle
https://gcanti.github.io/monocle-ts/
MIT License
1.05k stars 52 forks source link

Unable to set a new value to a Prism #144

Closed skysantalucial closed 4 years ago

skysantalucial commented 4 years ago

πŸ› Bug report

Hello! I stumbled on a problem while experimenting with the examples. Seems like setting a new value to a Prism is no more possible

Current Behavior

interface Person {
  name: string
  surname: Option<string>
}

const surname = Lens.fromProp<Person>()('surname').composePrism(Prism.some<string>())

const p: Person = { name: 'Giulio', surname: none }

console.log(surname.getOption(p)) // => None
console.log(surname.set('Canti')(p)) // => { name: 'Giulio', surname: None }

Expected behavior

interface Person {
  name: string
  surname: Option<string>
}

const surname = Lens.fromProp<Person>()('surname').composePrism(Prism.some<string>())

const p: Person = { name: 'Giulio', surname: none }

console.log(surname.getOption(p)) // => None
console.log(surname.set('Canti')(p)) // => { name: 'Giulio', surname: Some("Canti") }

Your environment

According to my tests this behavior appeared from version 2.0.1

Software Version(s)
monocle-ts 2.3.3
fp-ts 2.8.4
TypeScript 4.1.2
gcanti commented 4 years ago

@skysantalucial the current behavior is correct according to the Optional laws

  1. pipe(getOption(s), fold(() => s, a => set(a)(s))) = s
  2. getOption(set(a)(s)) = pipe(getOption(s), map(_ => a))
  3. set(a)(set(a)(s)) = set(a)(s)
skysantalucial commented 4 years ago

@gcanti Ok, so it's just a matter of updating the examples

In this case how can i go from this { name: 'Laura', surname: none } to this { name: 'Laura', surname: Some("Santalucia") } using an Optional? Is it possibile?

gcanti commented 4 years ago

Ok, so it's just a matter of updating the examples

Yup, thanks for pointing out.

using an Optional? Is it possibile?

No it isn't, you need a Lens

const surname = Lens.fromProp<Person>()('surname')

const p: Person = { name: 'Giulio', surname: none }

console.log(surname.set(some('Canti'))(p)) // => { name: 'Giulio', surname: Some("Canti") }
skysantalucial commented 4 years ago

understood πŸ‘ thanks for the help