Reputation: 35
Is there a way to get the element before the last using hakell lens? For example, I have such a structure:
pp = (1,2,3,4)
I want to do something like pp ^. _almostLast
and get 3
. I can't use _3 because (suppose) I don't know how much elements there are in this tuple.
Upvotes: 1
Views: 94
Reputation: 2615
If you want your code to be flexible over the number of elements in a tuple, one option is to create your own type class, similar to the Field2
class in Control.Lens.Tuple
, which provides the _2
function.
This class and the instances for the first few tuples look like this (after removing some comments and irrelevant code):
-- | Provides access to the 2nd field of a tuple.
class Field2 s t a b | s -> a, t -> b, s b -> t, t a -> s where
_2 :: Lens s t a b
instance Field2 (a,b) (a,b') b b' where
_2 k ~(a,b) = k b <&> \b' -> (a,b')
{-# INLINE _2 #-}
instance Field2 (a,b,c) (a,b',c) b b' where
_2 k ~(a,b,c) = k b <&> \b' -> (a,b',c)
{-# INLINE _2 #-}
instance Field2 (a,b,c,d) (a,b',c,d) b b' where
_2 k ~(a,b,c,d) = k b <&> \b' -> (a,b',c,d)
{-# INLINE _2 #-}
If we now want to make a variant which instead picks the second-to-last element, we just have to tweak the code to do that:
-- | Provides access to the 2nd to last field of a tuple.
class AlmostLast s t a b | s -> a, t -> b, s b -> t, t a -> s where
_almostLast :: Lens s t a b
instance AlmostLast (a,b) (a',b) a a' where
_almostLast k ~(a,b) = k a <&> \a' -> (a',b)
{-# INLINE _almostLast #-}
instance AlmostLast (a,b,c) (a,b',c) b b' where
_almostLast k ~(a,b,c) = k b <&> \b' -> (a,b',c)
{-# INLINE _almostLast #-}
instance AlmostLast (a,b,c,d) (a,b,c',d) c c' where
_almostLast k ~(a,b,c,d) = k c <&> \c' -> (a,b,c',d)
{-# INLINE _almostLast #-}
etc. for as many tuples you need.
But the big question here is: Why don't you know how long your tuple is? In most such cases, you would be much better off using a list, especially so you don't have to manually write a bunch of instances for each possible length of tuples you expect to encounter.
Upvotes: 1