To try to simplify this problem, I defined these arrow functions:
splitA :: (Arrow arr) => arr ab -> arr a (b,a) splitA ar = ar &&& (arr (\a -> id a)) recordArrow :: (Arrow arr) => (d -> r) -> (d -> r -> d) -> (r -> r) -> arr dd recordArrow gsf = splitA (arr g >>^ f) >>^ \(r,d) -> sdr
Which allows me to do something like this:
unarrow :: ((->) bc) -> (b -> c) -- unneeded as pointed out to me in the comments unarrow g = g data Testdata = Testdata { record1::Int,record2::Int,record3::Int } testRecord = unarrow $ recordArrow record1 (\dr -> d { record1 = r }) id >>> recordArrow record2 (\dr -> d { record2 = r }) id >>> recordArrow record3 (\dr -> d { record3 = r }) id
As you can see, this does not use DRY very well.
I hope there may be some kind of extension of the language that could simplify this process. So that the above could simply be rewritten as:
testRecord' = unarrow $ recordArrow' record1 id >>> recordArrow' record2 id >>> recordArrow' record3 id
Updated for clarity . To clarify a bit. I know I can do something like this:
foo d = d { record1 = id (record1 d), record2 = id (record2 d) }
But it ignores any order of execution and any state. Suppose the update function for record2 relies on the updated value for record1 . Or, alternatively, I can create another arrow that looks like this: arr d (d,x) , and then I want to create a list [x] , the order of which depends on the evaluation order of the records.
I found that I often want to perform some functions and subsequently update the record. I can do this by filling this state as follows
g :: d -> r -> d foo d = let d' = d { record1 = (gd) (record1 d) } in d' { record2 = (g d') (record2 d') }
But I think the arrow notation is neater, and I could also have [arr dd] and combine them into sequences. Plus, if r or d are Monads, it creates cleaner code. Or, if both of them are monads, this allows me to do layered bindings without using Monad Transformer. In the case of ST sx it allows us to order the state of s .
I am not trying to solve one specific problem. I'm just trying to find an abstracted method for updating the syntax of records without explicitly specifying a kind of "getter" and "setter".
The answers in the comments below were given below - Sidenote: I had to define a unarrow function to convert a function (->) back to a function. Otherwise, if I have someArrow b for the arrow arr bc , I cannot get the value c . With the unarrow function unarrow I can write unarrow someArrow b , and it works fine. It seems to me that I should do something wrong, because my definition for unarrow is simply unarrow g = g .