Using Traversal as a kind of pointer

Hi, I'm programming a small game - amongst my types I have a 'world' structure data World = World Background [Lifeform] I'm calculating collisions between my player and the lifeforms, and I'll need this result both to allow some actions and to modify the world as a result. I'm using FRP with elerea, so everything is defined as behaviours (signals), and the collision signal is used in the signal accounting of life spent and in the world signal. I was thinking of returning a Traversal on the lifeforms that are colliding so that I can both access the lifeforms concerned (when performing actions and life accounting) and modify them as a result (for the world). Does that sound reasonable as a use of lenses? Overengineered? Better solutions? Thank you, Elise Huard

Hi Elise, I'm not quite sure if I completely understood your use case, but if you only want to modify the lifeforms that are colliding with the player, then you could have something like: world & liveforms . filtered (collidingWith player) %~ \liveform -> ... with liveforms :: Lens' World [Lifeform] collidingWith :: Player -> Lifeform -> Bool I would consider this as a quite nice solution. Greetings, Daniel

Hi Daniel,
thanks for your answer. That looks like something that might work -
however, having never worked with Optics, I'm not entirely sure
whether I'm doing it right, getting an error:
*Main Graphics.Rendering.OpenGL Control.Lens> :t (liveforms . filtered
(colliding p))
<interactive>:1:14:
Couldn't match type _Lifeform_ with _[Lifeform]_
Expected type: (Lifeform -> f Lifeform)
-> [Lifeform] -> f [Lifeform]
Actual type: Optic' (->) f Lifeform Lifeform
In the second argument of _(.)_, namely
_filtered ((flip colliding) p)_
In the expression: (liveforms . filtered ((flip colliding) p))
*Main Graphics.Rendering.OpenGL Control.Lens>
Also, may I ask what the '&' is in your proposed solution?
Thanks,
Elise
On 18 August 2014 13:30, Daniel Trstenjak
Hi Elise,
I'm not quite sure if I completely understood your use case, but if you only want to modify the lifeforms that are colliding with the player, then you could have something like:
world & liveforms . filtered (collidingWith player) %~ \liveform -> ...
with
liveforms :: Lens' World [Lifeform]
collidingWith :: Player -> Lifeform -> Bool
I would consider this as a quite nice solution.
Greetings, Daniel _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

And just remember filtered is only a valid traversal if you don't change
the number of targets with the modification function!
On 18 August 2014 14:17, Elise Huard
Hi Daniel,
thanks for your answer. That looks like something that might work - however, having never worked with Optics, I'm not entirely sure whether I'm doing it right, getting an error: *Main Graphics.Rendering.OpenGL Control.Lens> :t (liveforms . filtered (colliding p))
<interactive>:1:14: Couldn't match type _Lifeform_ with _[Lifeform]_ Expected type: (Lifeform -> f Lifeform) -> [Lifeform] -> f [Lifeform] Actual type: Optic' (->) f Lifeform Lifeform In the second argument of _(.)_, namely _filtered ((flip colliding) p)_ In the expression: (liveforms . filtered ((flip colliding) p)) *Main Graphics.Rendering.OpenGL Control.Lens>
Also, may I ask what the '&' is in your proposed solution? Thanks,
Elise
On 18 August 2014 13:30, Daniel Trstenjak
wrote: Hi Elise,
I'm not quite sure if I completely understood your use case, but if you only want to modify the lifeforms that are colliding with the player, then you could have something like:
world & liveforms . filtered (collidingWith player) %~ \liveform ->
...
with
liveforms :: Lens' World [Lifeform]
collidingWith :: Player -> Lifeform -> Bool
I would consider this as a quite nice solution.
Greetings, Daniel _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

Hi Elise,
thanks for your answer. That looks like something that might work - however, having never worked with Optics, I'm not entirely sure whether I'm doing it right, getting an error:
oh sorry, there has to be a 'traversed' before the 'filtered'.
Also, may I ask what the '&' is in your proposed solution?
The '&' is just applying a lens to a variable. So here's a working example: {-# LANGUAGE Rank2Types #-} import Control.Lens type Background = Int type Lifeform = Int type Player = Int data World = World Background [Lifeform] deriving (Show) lifeforms :: Lens' World [Lifeform] lifeforms = lens getLifeforms setLifeforms where getLifeforms (World _ lifeforms) = lifeforms setLifeforms (World bg _) lifeforms = World bg lifeforms colliding :: Player -> Traversal' [Lifeform] Lifeform colliding player = traversed . filtered (== player) If you load this into ghci und can write:
World 1 [1, 2] & lifeforms . colliding 1 %~ (+ 10) World 1 [11,2]
Greetings, Daniel

Thanks for the example! I found another example of filtered here
http://www.haskellforall.com/2013/05/program-imperatively-using-haskell.html
I'm aware that filtered traversals should only ever be used with
functions that will not change the number of elements filtered.
Thank you!
Elise
On 18 August 2014 16:03, Daniel Trstenjak
Hi Elise,
thanks for your answer. That looks like something that might work - however, having never worked with Optics, I'm not entirely sure whether I'm doing it right, getting an error:
oh sorry, there has to be a 'traversed' before the 'filtered'.
Also, may I ask what the '&' is in your proposed solution?
The '&' is just applying a lens to a variable.
So here's a working example:
{-# LANGUAGE Rank2Types #-}
import Control.Lens
type Background = Int type Lifeform = Int type Player = Int
data World = World Background [Lifeform] deriving (Show)
lifeforms :: Lens' World [Lifeform] lifeforms = lens getLifeforms setLifeforms where getLifeforms (World _ lifeforms) = lifeforms setLifeforms (World bg _) lifeforms = World bg lifeforms
colliding :: Player -> Traversal' [Lifeform] Lifeform colliding player = traversed . filtered (== player)
If you load this into ghci und can write:
World 1 [1, 2] & lifeforms . colliding 1 %~ (+ 10) World 1 [11,2]
Greetings, Daniel _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (3)
-
Benjamin Edwards
-
Daniel Trstenjak
-
Elise Huard