Zulip Chat Archive

Stream: new members

Topic: or-else in monadic assignment


Eric Wieser (Feb 28 2021 at 18:27):

If I write

example : tactic (option nat) :=
do
  t  foo <|> return none,
  bar,
  return (some 1)

this means "set t to foo, or set it to none if foo fails, then run bar then baz". I can understand why it means this, but it's not the behavior I'm looking for.

How do I write "set t to foo. If this fails, then exit the monad and produce none. Otherwise, continue with bar then baz"

Eric Wieser (Feb 28 2021 at 18:28):

That is, I'm looking for how to translate this python:

try:
    t = foo()
except:
    return None
bar()
return some(1)

but only know how to write

try:
    t = foo()
except:
    t = None
bar()
return some(1)

Yakov Pechersky (Feb 28 2021 at 18:30):

example : tactic (option nat) :=
(do
  t  foo,
  bar,
  return (some 1)) <|> return none

?

Yakov Pechersky (Feb 28 2021 at 18:34):

What's the type of foo? How many such exits do you expect to have in your control flow?

Eric Wieser (Feb 28 2021 at 18:37):

Right, but that code is

try:
    t = foo()
    bar()
    return some(1)
except:
    return none

which also squashes errors from bar, which I don't want to do

Eric Wieser (Feb 28 2021 at 18:38):

Let's say that foo is tactic nat

Yakov Pechersky (Feb 28 2021 at 18:41):

Do you want a different error value if bar fails?

Eric Wieser (Feb 28 2021 at 18:43):

I want the error from bar to propagate

Mario Carneiro (Mar 01 2021 at 08:24):

I think you are looking for t ← foo | return none,

Mario Carneiro (Mar 01 2021 at 08:26):

Actually I think that only works on failed pattern matches, so you might have to rewrite it to some t <- try_core foo | return none, if you want to catch errors in foo

Eric Wieser (Mar 01 2021 at 08:31):

docs#tactic.try_core sounds like what I was looking for

Eric Wieser (Mar 01 2021 at 08:38):

What does pattern matching desugar to in assignment?

Mario Carneiro (Mar 01 2021 at 08:44):

It's a pattern match with a wildcard case

Mario Carneiro (Mar 01 2021 at 08:44):

i.e.

o <- try_core foo,
match o with
| some t := do <rest of the do block>
| _ := return none
end

Mario Carneiro (Mar 01 2021 at 08:46):

In the case of an alternative monad (like tactic) you can also leave off the | ... part, and it will use failure as the else case

Eric Wieser (Mar 01 2021 at 09:01):

Can you pattern match with multiple non-wildcard cases?

Eric Wieser (Mar 01 2021 at 09:01):

Or is the | syntax exclusively for "one case + default"?

Eric Wieser (Mar 01 2021 at 09:11):

And I guess my other question - where is this syntax documented?

Ruben Van de Velde (Mar 01 2021 at 09:21):

I would have guessed https://leanprover.github.io/reference/programming.html#monads

Mario Carneiro (Mar 01 2021 at 11:47):

There is no syntax for binding anything, so I would guess it's only for one pattern plus "anything else"

kana (Mar 01 2021 at 12:46):

yeah, such syntax from idris/agda will be great

do pattern1 <- a
     | pattern2 := b
     | pattern3 := c, -- should be total
   e

=

a >>= fun x,
  match x with
  | pattern1 := e
  | pattern2 := b
  | pattern3 := c
  end

like

variable get_name : io (option string)

def main := do
  some a  get_name | none := io.put_str_ln "fail on first name",
  some b  get_name | none := io.put_str_ln "fail on second name",
  io.put_str_ln (a ++ b)

Eric Wieser (Mar 01 2021 at 12:50):

I think some of the ->s in your example were intended to be :=?

kana (Mar 01 2021 at 12:51):

Yes, fixed

Mario Carneiro (Mar 01 2021 at 14:23):

I don't think this is worth investigating in lean 3, and lean 4 do blocks are so different that it's not clear to me whether this even applies anymore

Eric Wieser (Mar 01 2021 at 14:24):

Agreed, the only thing that might be worth doing is documenting that this syntax exists somewhere

Eric Wieser (Mar 01 2021 at 15:45):

Done in https://github.com/leanprover-community/leanprover-community.github.io/pull/174

kana (Mar 01 2021 at 17:38):

Oh, there are no way to match in else clause? Why the feature is so specialized?

Mario Carneiro (Mar 02 2021 at 02:54):

If you want a match, use match. I think of this feature as more like rust's if let, which gives you two branches, one if a given pattern matches and one for everything else


Last updated: Dec 20 2023 at 11:08 UTC