apfelmus schrieb:
Benedikt Huber wrote:
So, the Ref deriviation is really nice for sequential updates;
parallel updates on the other hand need some work.
..
While the select part of the Ref is expressed using &&&, I don't know
how the
parallel update can be expressed in terms of combinators. Any hints ?

You can't do that, and for good reason! While

  players :: Lens Game (Player,Player)

is entirely fine since  Game ~ (Player,Player,Object2D), there cannot be
a general parallel combinator

  (&&&) :: Lens a b -> Lens a c -> Lens a (b,c)

Thanks for the nice overview.
I see there can't be a general purpose combinator (&&&) for lenses.
One could still define a helper function though:

combineDisjoint :: Lens a b -> Lens a c -> Lens a (b,c)
combineDisjoint l1 l2 = Lens $ select &&& update
  where
    select = (fst . focus l1) &&& (fst . focus l2)
    update cx (a,b) = flip (snd . focus l2) b $ (snd . focus l1) cx a

which performs the first update using the initial context, and the
second one using the updated context. Just to have a simple way of
defining lensPlayers in term of lensPlayer1 `combineDisjoint`
lensPlayer2. While it is not a (general purpose) combinator, it is still
helpfull for combining lenses focusing on fields of a record.

--

I just want to rephrase my question about paralell updates; it has more
to do with records updates than with References / Lenses, though:

Suppose we have a record

data R = R { a:: A, b :: B, c :: C } deriving (Show {-! Ref !-})

and update functions

fa :: a -> a, fb :: b -> b, fc :: c -> c

Now the standard way to perform the update on R would be

updateR = \r@(R {a=a,b=b,c=c}) -> r { a = fa a,b = fb b,c = fc c }

which is 'a little bit' cumbersome.


With update deriviations (like Update using DrIFT), references (Ref using Data.Derive) or lenses it is easy to perform the update sequentially (using DrIFT style for simplicity):

updateR' = a_u fa . b_u fb . c_u fc

But this corresponds to

updateR' = (\f r -> r { a = f (a r) }) fa .
           (\f r -> r { b = f (b r) }) fb .
           (\f r -> r { c = f (c r) }) fc

which (in some way) is not 'the same' as updateR.

First, I (uneducatedly) guess that the record updates cannot be 'executed' in paralell, i.e. the record has to be deconstructed and build up again three times. And second, neither the types of the updates (e.g. a_u fa :: R -> R) nor the structure of updateR' (composing R->R functions) do reflect the fact
that actually disjoint fields of the record are updated.


Now I know there are great record proposals (which extend the haskell
language or use some type hackery), but I wondered if there is also a
solution which can be used right now and which works fine with the
standard record types.

I'll give a naive ad-hoc example to illustrate the idea.
One could automatically derive the following data type and the
associated functions for R:

data R_upd = R_upd { updA :: A -> A, updB :: B -> B, updC :: C -> C }
rUpd = R_upd id id id
updR :: R_upd -> R -> R
updR rupd r@(R { a=a,b=b,c=c }) = r
  { a = (updA rupd a),
    b = (updB rupd b),
    c = (updC rupd c) }

which would allow to write things like

updGame $
  gameUpdate { updPlayer1 = increaseScore, updPlayer2 = decreaseScore })

Though simple, I hope it is possible to understand the idea (I know there is a lot of namespace pollution).
And of course, someone has thought of something much more sophistacted
already :)
What are the drawbacks of such an approach ?

thanks,
benedikt


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to