To try and simplify this problem I have defined these arrow functions:

``splitA :: (Arrow arr) => arr a b -> arr a (b,a)splitA ar = ar &&& (arr (\a -> id a))recordArrow:: (Arrow arr)=> (d -> r)-> (d -> r -> d)-> (r -> r)-> arr d drecordArrow g s f = splitA (arr g >>^ f) >>^ \(r,d) -> s d r``

Which then let's me do something like this:

``unarrow :: ((->) b c) -> (b -> c) -- unneeded as pointed out to me in the commentsunarrow g = gdata Testdata = Testdata { record1::Int,record2::Int,record3::Int }testRecord = unarrow \$recordArrow record1 (\d r -> d { record1 = r }) id>>> recordArrow record2 (\d r -> d { record2 = r }) id>>> recordArrow record3 (\d r -> d { record3 = r }) id``

As you can see this doesn't make very good use of DRY.

I'm hoping there might be some sort of language extension that could help simplify this process. So that the above could simply be re-written as:

``testRecord' = unarrow \$recordArrow' record1 id>>> recordArrow' record2 id>>> recordArrow' record3 id``

Updated for clarity: To clarify a little bit. I'm aware that I could do something like this:

``foo d = d { record1 = id (record1 d), record2 = id (record2 d) }``

But this ignores any execution order and any state. Suppose the update function for `record2` relies on the updated value for `record1`. Or alternatively, I may want to create a different arrow that looks like this: `arr d (d,x)` and then I want to build a list of `[x]` the order of which depends on the evaluation order of the records.

What I've found is that I frequently want to execute some functionality and afterwards update a record. I can do that by threading the state like this

``g :: d -> r -> dfoo d = let d' = d { record1 = (g d) (record1 d) } in d' { record2 = (g d') (record2 d') }``

But I think arrow notation is neater, and I could also have `[arr d d]` and chain them together in a sequence. Plus if `r` or `d` are Monads it creates neater code. Or if they're both Monads, it let's me perform layered binds without having to use a Monad Transformer. In the case of `ST s x` it let's me thread the state `s` around in an ordered way.

I'm not trying to solve one particular problem. I'm just trying to find an abstracted method of updating a record syntax without having to explicitly define some sort of "getter" and "setter".

Sidenote: I've had to define a function `unarrow` for converting a function (->) arrow back to a function. Otherwise if I have `someArrow b` for an arrow `arr b c` I can't get to value `c`. With the `unarrow` function I can write `unarrow someArrow b` and it works fine. I feel like I must be doing something wrong here because my definition for unarrow is simply `unarrow g = g`.

The abstraction you are looking for is called a lens and the `lens` package on Hackage is probably the most widespread implementation of the idea currently in use. Using the `lens` package you can define your `recordArrow'` as

``````{-# LANGUAGE RankNTypes #-}

import Control.Arrow
import Control.Lens

recordArrow' :: Arrow arr => Lens' d r -> (r -> r) -> arr d d
recordArrow' field f = arr \$ field %~ f
``````

The `%~` is an update operator which updates a values inside a larger data structures using a function via the given lens.

Now the problem is that you don't automatically get lenses for your record fields, but you can either manually define them or generate them automatically using Template Haskell. For example

``````{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Testdata = Testdata { _record1::Int, _record2::Int, _record3::Int }

makeLenses ''Testdata
``````

Note that the original record accessors are prefixed with underscores so that we can use the original names for the lenses.

``````testRecord :: Testdata -> Testdata
testRecord =
recordArrow' record1 id
>>> recordArrow' record2 id
>>> recordArrow' record3 id
``````

The `unarrow` function is not needed. It's better to force a generic type to a concrete type by simple giving a type signature.

Note that if you are just looking for a nicer syntax to chain record operations and don't have any other use for arrows, you might prefer just to use the `State` monad with lenses. For example:

``````import Control.Monad.State (execState)

testRecord' :: Testdata -> Testdata
testRecord' = execState \$ do
record1 .= 3
record2 %= (+5)
record3 += 2
``````

Top