10

A lot of lens getters return Maybe values. And i often need to replace them with some default.

Say map lookup but with default.

fromMaybe "" $ Map.fromList [(1,"Foo")] ^? at 1

Can this be written with lens syntax? Maybe something close to this:

Map.fromList [(1,"Foo")] ^? at 1.or ""
Vagif Verdi
  • 4,816
  • 1
  • 26
  • 31

1 Answers1

10

I think what you want is

non :: Eq a => a -> Iso a (Maybe a)

non foo essentially does

 case someMaybe of
   Nothing -> foo
   Just a  -> a

In your case

 someMap ^. at 1 . non ""

Coincidentally, this is precisely the example of non the docs give.

If you want to use this with ix you're out of luck, but you can always do

 -- Import Data.Monoid
 defaulting :: a -> s -> Getting (First a) s a -> a
 defaulting a s fold = fromMaybe a $ s ^? fold

 foo = defaulting 0 [1, 2, 3] $ ix 3 -- 0
daniel gratzer
  • 52,833
  • 11
  • 94
  • 134
  • Awesome thanks!. Works as i want. I wonder though why they named it non? Weird name. "or" would have been so much more clearer. – Vagif Verdi Feb 28 '14 at 04:14
  • @VagifVerdi It's supposed to be a mapping of `a` without whatever value supplied to `Maybe a` so in that sense it makes a bit more sense – daniel gratzer Feb 28 '14 at 04:15
  • Hmm, turns out does not work in some cases. Works with ^. at, does not work with ^? ix. Is there a way to apply it somehow to ix? – Vagif Verdi Feb 28 '14 at 04:18
  • @VagifVerdi I think not, this is a map from `Maybe a` to `a`, but `ix` relies on an underlying monoid do use for failure, so if it fails it will never even pass the result to `non`. – daniel gratzer Feb 28 '14 at 04:28
  • If I may ask, why are you using `ix`? – daniel gratzer Feb 28 '14 at 04:28
  • fromMaybe 0 (someList ^? ix 0._1) i'm taking the first element of the list. BUt of course list can be empty. – Vagif Verdi Feb 28 '14 at 04:33
  • @VagifVerdi Yes, nothing can compose with something like `ix` and save it from failing if I understand lens correctly since it's going to fail part way through the chain (as a demonstration, stick an `Debug.Trace.trace` in there and see that things aren't evaluated). So that's the bad news, the good news is you can just define a combinator to wrap around `fromMaybe foo $ quux ^? baz` trivially. – daniel gratzer Feb 28 '14 at 04:38