Is it possible to construct a new record using Lenses?
Asked Answered
T

1

8

If I have a record type with lenses, is it possible to construct a new record without using the underlying record accessors?

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens
import Control.Lens.TH

data Foo = Foo { _s :: String
               , _b :: Bool
               } deriving (Show, Eq)

makeLenses ''Foo

I could make Foo an instance of Data.Default and then modifiy def with lenses, but not all record types will have sensible defaults. Does Control.Lens have its own way to do it?

Tanjatanjore answered 25/8, 2013 at 15:2 Comment(7)
You could always use Foo{} as default, leaving all fields undefined.Wisent
Thanks! I didn't even know you could omit fields there. I just assumed it would be a compile error.Tanjatanjore
Note that this won't work if Foo has strict fields.Magisterial
Good point @shachaf, I didn't consider that. So Default instance is required for strict fields and therefore probably is the correct way to go in general to avoid fragile code.Tanjatanjore
Also note that you run into an issue with type-changing lenses. E.g. for data Foo a = Foo { _x, _y :: a }, the lenses x and y individually can't change the type, since you have to modify the fields x and y at once.Magisterial
(There's a proposed mechanism that could be used to make type-changing lenses that would work there, but I don't think anyone's written code for it so far.)Magisterial
So, in conclusion: This is a minefield! :)Tanjatanjore
S
6

No, there is currently no way to do that. You'll have to use something like Foo{} as default or not use lens for record construction. However, there is already an issue in lens covering this.

Sapphism answered 25/8, 2013 at 15:40 Comment(1)
Thanks for link to the github ticket. Some interesting discussion there!Tanjatanjore

© 2022 - 2024 — McMap. All rights reserved.