[Haskell-cafe] Conditional lens

2013-10-10 Thread Artyom Kazak

Hello!

I am working with TypeReps, and while writing some functions I have
noticed that I could use lenses to simplify them; however, I have stumbled
upon some difficulties.

First I’ll try to clarify which functions I want to write:

* a function for converting TypeRep of, say, `Maybe x` to `[x]`
  (for all x). It requires checking if the TyCon is `Maybe` and
  replacing it with []-TyCon. If it wasn’t `Maybe`, I return Nothing.

* a similar function for replacing `Char`s and `Lazy.Text`s to just
  `Text`. Again, if the TypeRep-to-be-replaced doesn’t satisfy my
  conditions, I return Nothing.

These two functions (and some others, I suppose) can be written concisely
with the help of one combinator. I don’t know how to write it as
a composable Lens, so I’ll give it here as an ad-hoc Lens-modifying
function instead:

ifL :: (a - Bool) - Lens s t a b - Lens s (Maybe t) (Maybe a) b
ifL p l = lens getter setter
  where
get s = getConst $ l Const s
getter s   = let a = get s
 in  if p a then Just a else Nothing
setter s b = let a = get s
 in  if p a then Just (set l b s) else Nothing

It works like this:

 (0, 2)  ifL even fs .~ hello
Just (hello,2)

 (1, 2)  ifL even fs .~ hello
Nothing

With `ifL`, my initial ugly

changeTyCon :: TyCon - TyCon - TypeRep - Maybe TypeRep
changeTyCon tc tc' t | t^.tyCon == tc = Just $ t  tyCon .~ tc'
 | otherwise  = Nothing

boils down to

changeTyCon tc tc' = ifL (== tc) tyCon .~ tc'

Why did I call the initial version “ugly”? Well, because

a) it manually handles `Maybe`s, and
b) it has to perform both getting and setting (two passes).

So, my questions are:

1. What would be the idiomatic way to write `ifL`?

2. How can I do something like `t ^. ifL (== tc) tyCon`?
   Currently it doesn’t work because view’s type has been
   simplified in lens-3.9.

3. Perhaps it would be better to represent `ifL` as a Traversal
   which simply ignores values that don’t match the condition?
   Then I could (?) use `failover` to do what I want. I searched
   for something filter-like in lens library, but haven’t found
   anything.

4. If I haven’t missed anything and it indeed can’t be done with bare
   lens, would `ifL` or something similar be welcome as an addition
   to the library?

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


Re: [Haskell-cafe] Conditional lens

2013-10-10 Thread Edward Kmett
`ifL` isn't a legal lens for several reasons.

Lens s t a b generally requires that the types a subsumes b and b subsumes
a, and that s subsumes t and t subsumes s.

Lens s (Maybe t) (Maybe a) b is a huge red flag.

There is an 'illegal prism' provided by lens that is a more principled
version of this, however.

 (0,2)  _1.filtered even .~ 2

(2,2)
filtered only claims to be a Fold, because that is all it can legally claim
to pass the laws for, however it is implemented in such a way that you can
use it as a Traversal or even a Prism. To sleep soundly you should ensure
that the elements you write back pass the filter function as True,
otherwise you'll violate a law and the lens police will come for you in the
night.

You can of course implement the method you want without any of these
shenanigans and still sleep well at night, though.

changeTyCon tc tc' = tyCon $ \a - if a == tc then Just tc' else Nothing

changeTyCon tc tc' = tyCon $ \a - tc' $ guard (a == tc)

-Edward



On Thu, Oct 10, 2013 at 5:00 PM, Artyom Kazak y...@artyom.me wrote:

 Hello!

 I am working with TypeReps, and while writing some functions I have
 noticed that I could use lenses to simplify them; however, I have stumbled
 upon some difficulties.

 First I’ll try to clarify which functions I want to write:

 * a function for converting TypeRep of, say, `Maybe x` to `[x]`
   (for all x). It requires checking if the TyCon is `Maybe` and
   replacing it with []-TyCon. If it wasn’t `Maybe`, I return Nothing.

 * a similar function for replacing `Char`s and `Lazy.Text`s to just
   `Text`. Again, if the TypeRep-to-be-replaced doesn’t satisfy my
   conditions, I return Nothing.

 These two functions (and some others, I suppose) can be written concisely
 with the help of one combinator. I don’t know how to write it as
 a composable Lens, so I’ll give it here as an ad-hoc Lens-modifying
 function instead:

 ifL :: (a - Bool) - Lens s t a b - Lens s (Maybe t) (Maybe a) b
 ifL p l = lens getter setter
   where
 get s = getConst $ l Const s
 getter s   = let a = get s
  in  if p a then Just a else Nothing
 setter s b = let a = get s
  in  if p a then Just (set l b s) else Nothing

 It works like this:

  (0, 2)  ifL even fs .~ hello
 Just (hello,2)

  (1, 2)  ifL even fs .~ hello
 Nothing

 With `ifL`, my initial ugly

 changeTyCon :: TyCon - TyCon - TypeRep - Maybe TypeRep
 changeTyCon tc tc' t | t^.tyCon == tc = Just $ t  tyCon .~ tc'
  | otherwise  = Nothing

 boils down to

 changeTyCon tc tc' = ifL (== tc) tyCon .~ tc'

 Why did I call the initial version “ugly”? Well, because

 a) it manually handles `Maybe`s, and
 b) it has to perform both getting and setting (two passes).

 So, my questions are:

 1. What would be the idiomatic way to write `ifL`?

 2. How can I do something like `t ^. ifL (== tc) tyCon`?
Currently it doesn’t work because view’s type has been
simplified in lens-3.9.

 3. Perhaps it would be better to represent `ifL` as a Traversal
which simply ignores values that don’t match the condition?
Then I could (?) use `failover` to do what I want. I searched
for something filter-like in lens library, but haven’t found
anything.

 4. If I haven’t missed anything and it indeed can’t be done with bare
lens, would `ifL` or something similar be welcome as an addition
to the library?

 Thanks!

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