Zulip Chat Archive

Stream: lean4

Topic: when args argue inhabited


James Gallicchio (Apr 11 2023 at 20:10):

is there a way to get something like this to compile?

partial def foldl [mi: Monad m] [ai: Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  (do let base'  rightCont base; foldl base' rightCont) <|> (pure base)

The argument base justifies the type is inhabited, with pure base as its element.

Adam Topaz (Apr 11 2023 at 20:18):

(deleted)

Adam Topaz (Apr 11 2023 at 20:18):

sorry, forgot the recursion. I'll fix it in a few mins

Adam Topaz (Apr 11 2023 at 20:20):

oh nevermind, using ascii art gives the same issues

Adam Topaz (Apr 11 2023 at 20:20):

But this works for some reason:

partial def foldl [Monad m] [Alternative m] [Inhabited γ] (base : γ) (rightCont : γ  m γ) : m γ :=
  (rightCont base >>= fun b => foldl b rightCont) <|> (pure base)

Adam Topaz (Apr 11 2023 at 20:21):

(it also works with do)

James Gallicchio (Apr 11 2023 at 20:30):

I think that's from the [Inhabited γ] argument

James Gallicchio (Apr 11 2023 at 20:30):

which is what I'm trying to avoid

Gabriel Ebner (Apr 11 2023 at 20:32):

Check set_option trace.Meta.synthInstance true

Gabriel Ebner (Apr 11 2023 at 20:32):

I believe the partial command searches for Nonempty (full function type) as well.

James Gallicchio (Apr 11 2023 at 20:34):

It does look for Inhabited ([mi : Monad m] → [ai : Alternative m] → γ → (γ → m γ) → m γ), but tc synth can't instantiate it, it seems

James Gallicchio (Apr 11 2023 at 20:34):

(I wouldn't expect it to, either)

James Gallicchio (Apr 11 2023 at 20:35):

Frankly I am pretty okay if this doesn't work fully automatically -- the more annoying thing is that there's no way for me to provide the Nonempty (full function type) instance for it to use.

James Gallicchio (Apr 11 2023 at 20:35):

(other than by making a global instance right before the def)

James Gallicchio (Apr 11 2023 at 20:36):

I guess I can do this:

instance : Inhabited ([mi : Monad m]  [ai : Alternative m]  γ  (γ  m γ)  m γ) := λ g _ => pure g in
partial def foldl [mi: Monad m] [ai: Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  (do let base'  rightCont base; foldl base' rightCont) <|> (pure base)

James Gallicchio (Apr 11 2023 at 20:37):

so that the instance doesn't escape scope... but then I'm a bit annoying that I have to copy/paste the type there.

James Gallicchio (Apr 11 2023 at 20:38):

But that works for me for now. Thanks!

Gabriel Ebner (Apr 11 2023 at 20:38):

You can do local instance, but you still need to retype the type.

Gabriel Ebner (Apr 11 2023 at 20:38):

Instance .. in is a big foot gun

Gabriel Ebner (Apr 11 2023 at 20:39):

It means exactly the same as instance without the in.

Gabriel Ebner (Apr 11 2023 at 20:40):

Another gotcha is private instance.

Adam Topaz (Apr 11 2023 at 20:46):

How about this?

partial def foldl_aux [Monad m] [Alternative m] [Inhabited γ] (base : γ) (rightCont : γ  m γ) : m γ :=
  (rightCont base >>= fun b => foldl_aux b rightCont) <|> (pure base)

partial def foldl [Monad m] [Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  letI : Inhabited γ := base
  foldl_aux base rightCont

Adam Topaz (Apr 11 2023 at 20:46):

I tried to put Inhabited somewhere inline within foldl, but couldn't get it to work. Maybe Gabriel knows some other tricks?

Adam Topaz (Apr 11 2023 at 20:48):

Oh this works:

partial def foldl [Monad m] [Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  let rec go [_h : Inhabited γ] (bs : γ) (rc : γ  m γ) : m γ :=
    (rc bs >>= fun b => go b rc) <|> (pure bs)
  go (_h := base⟩) base rightCont

Adam Topaz (Apr 11 2023 at 20:51):

using where also works:

partial def foldl [Monad m] [Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  go (_h := base⟩) base rightCont
  where go [_h : Inhabited γ] (bs : γ) (rc : γ  m γ) : m γ :=
    (rc bs >>= fun b => go b rc) <|> (pure bs)

Gabriel Ebner (Apr 11 2023 at 21:08):

I would recommend

instance [Alternative m] : Nonempty (m α) := failure

partial def foldl [Monad m] [Alternative m] (base : γ) (rightCont : γ  m γ) : m γ :=
  (do let base'  rightCont base; foldl base' rightCont) <|> (pure base)

Gabriel Ebner (Apr 11 2023 at 21:23):

Even if you don't have Alternative, then you can still get away without writing the precise function type twice:

local instance : Nonempty (α  (α  β)  β) := ⟨(· |> ·)⟩ in
partial def foldl' [Monad m] (base : γ) (rightCont : γ  m γ) : m γ := do
  foldl' ( rightCont base) rightCont

James Gallicchio (Apr 11 2023 at 21:58):

hm, okay


Last updated: Dec 20 2023 at 11:08 UTC