1
votes

I am trying to use purescript-lens to update a property of a nested record. However, when I compose lenses to get to the property, I get the following type error:

Warning: Error at src/Main.purs line 150, column 38 - line 152, column 3: 
Error in declaration performAction
Cannot unify { description :: u24500 | u24501 } with Main.Item. Use --force to continue.

I'm relatively new to lenses and purescript, so it's probably something simple and obvious.

The relevant code that produces this error follows (yes, it's based on purescript-thermite-todomvc):

data Action
  = NewItem String String String String String
  | RemoveItem Index
  | SetEditText String
  | DoNothing

data Item = Item
            { description :: String
            , keywords :: String
            , link_title :: String
            , profile :: String
            , title :: String
            }

data State = State
  { item :: Item
  , editText :: String
  }

_State :: LensP State { item :: _, editText :: _ }
_State f (State st) = State <$> f st

item :: forall r. LensP { item :: _ | r } _
item f st = f st.item <#> \i -> st { item = i }

editText :: forall r. LensP { editText :: _ | r } _
editText f st = f st.editText <#> \i -> st { editText = i }

itemDescription :: forall r. LensP { description :: _ | r } _
itemDescription f it = f it.description <#> \d -> it { description = d }

performAction :: T.PerformAction _ Action (T.Action _ State)
performAction _ action = T.modifyState (updateState action)
  where
  updateState :: Action -> State -> State
  updateState (NewItem s1 _ _ _ _) = _State .. item .. itemDescription .~ s1
  updateState (SetEditText s)    = _State .. editText .~ s
  updateState DoNothing          = id

The property I'm trying to update is st.item.description and the above error refers to the line that starts "updateState (NewItem..." Curiously, the same error is also reported for the next line.

Any ideas on how to resolve the type error?

Thanks

1

1 Answers

0
votes

I've "fixed" this by making the types of the lenses less general. I've also based the lenses on the syntax that Phil uses in his "24 days" review of purescript-lens. I find that syntax less opaque.

item :: LensP State Item
item = lens (\(State st) -> st.item) (\(State st) item -> State (st { item = item }))

editText :: LensP State String
editText = lens (\(State st) -> st.editText) (\(State st) editText -> State (st { editText = editText }))

itemDescription :: LensP Item String
itemDescription = lens (\(Item it) -> it.description) (\(Item it) description -> Item (it { description = description }))

Again, to keep the lens types simple, I've stripped out the use of the _State lens in performAction:

performAction :: T.PerformAction _ Action (T.Action _ State)
performAction _ action = T.modifyState (updateState action)
  where
  updateState :: Action -> State -> State
  updateState (NewItem s1 _ _ _ _) = \st -> st # item..itemDescription.~ s1
  updateState (SetEditText s)    = \st -> st # editText.~ s
  updateState DoNothing          = id

I'm sure there's a more elegant, general, and complete solution, but that will have to wait until I understand purescript-lens better.