Zulip Chat Archive

Stream: lean4

Topic: Monad over prop?


James Gallicchio (Jun 20 2022 at 16:55):

Is there a reason monads can't be defined for constructors of type Sort u -> Type v instead of Type u -> Type v?

I tried redefining them over sort, but ended up with a strange error message about default implementations having metavariables. MWE:

class PBind (m : Sort u  Type v) where
  bind : {p q : Sort u}  m α  (α  m β)  m β

class PPure (f : Sort u  Type v) where
  pure {α : Sort u} : α  f α

class PFunctor (f : Sort u  Type v) : Type (max (u+1) v) where
  map      : {α β : Sort u}  (α  β)  f α  f β

class PApplicative (f : Sort u  Type v) extends PFunctor f, PPure f

class PMonad (m : Sort u  Type v) extends PApplicative m, PBind m : Type (max (u+1) v) where
  map {α β} f x := PBind.bind x fun a => PPure.pure (f a)

Henrik Böving (Jun 20 2022 at 16:59):

Making a Monad that operates on Prop doesn't seem too useful to me, consider:

  pure {α : Sort u} : α  f α

if α is from Prop this cannot be a regular function that eliminates into meaningful data (i.e. Type u) due to proof irrelevance right?

Mario Carneiro (Jun 20 2022 at 17:00):

I get a unused variable warning on p q : Sort u in bind, that should be a clue

Mario Carneiro (Jun 20 2022 at 17:00):

if you remove them then it compiles

James Gallicchio (Jun 20 2022 at 17:01):

oh LOL I renamed them and never changed the uses... thanks

James Gallicchio (Jun 20 2022 at 17:05):

Henrik Böving said:

if α is from Prop this cannot be a regular function that eliminates into meaningful data (i.e. Type u) due to proof irrelevance right?

Not computationally useful data, no. In my use case I have some computationally useful data (whether a test passed or not) but I'm also carrying proof terms around to make sure I'm actually testing the property I say I'm testing.

Henrik Böving (Jun 20 2022 at 17:06):

Oh that's fun yes, I did some work regarding this over here: https://github.com/leanprover-community/mathlib4/tree/master/Mathlib/Testing/SlimCheck

James Gallicchio (Jun 20 2022 at 17:08):

Yes, exactly that! :big_smile:

James Gallicchio (Jun 20 2022 at 17:11):

After fixing the typo mario pointed out, it seems like everything is working fine. So now I'm wondering why Monad in the prelude isn't defined for type constructors on Prop (@Leonardo de Moura ?)

It'd be nice to be able to use do notation on my structure.

Drop in replacement:

namespace Hidden

class Bind (m : Sort u  Type v) where
  bind : {α β : Sort u}  m α  (α  m β)  m β

class Pure (f : Sort u  Type v) where
  pure {α : Sort u} : α  f α

class Functor (f : Sort u  Type v) : Type (max (u+1) v) where
  map      : {α β : Sort u}  (α  β)  f α  f β
  mapConst : {α β : Sort u}  α  f β  f α := Function.comp map (Function.const _)

class Seq (f : Sort u  Type v) : Type (max (u+1) v) where
  seq  : {α β : Sort u}  f (α  β)  (Unit  f α)  f β

class SeqLeft (f : Sort u  Type v) : Type (max (u+1) v) where
  seqLeft : {α β : Sort u}  f α  (Unit  f β)  f α

class SeqRight (f : Sort u  Type v) : Type (max (u+1) v) where
  seqRight : {α β : Sort u}  f α  (Unit  f β)  f β

class Applicative (f : Sort u  Type v) extends Functor f, Pure f, Seq f, SeqLeft f, SeqRight f where
  map      := fun x y => Seq.seq (Pure.pure x) fun _ => y
  seqLeft  := fun a b => Seq.seq (Functor.map (Function.const _) a) b
  seqRight := fun a b => Seq.seq (Functor.map (Function.const _ id) a) b

class Monad (m : Sort u  Type v) extends Applicative m, Bind m : Type (max (u+1) v) where
  map      {α β} f x := Bind.bind x (fun a => Pure.pure (f a))
  seq      {α β} f x := Bind.bind f fun y => Functor.map y (x ())
  seqLeft  {α β} x y := Bind.bind x fun a => Bind.bind (y ()) (fun _ => Pure.pure a)
  seqRight {α β} x y := Bind.bind x fun _ => y ()

Mario Carneiro (Jun 20 2022 at 17:33):

I don't see an issue with this generalization on its own, although I have significant doubts about its usefulness

Leonardo de Moura (Jun 20 2022 at 23:22):

@James Gallicchio

So now I'm wondering why Monad in the prelude isn't defined for type constructors on Prop (@Leonardo de Moura ?

As Mario pointed out, it didn't look very useful. BTW, I don't have time to investigate the impact of this change right now.

Mario Carneiro (Jun 21 2022 at 00:05):

To elaborate more on why it isn't very useful: a monad with type Prop -> Type can only be used to bind propositions. You almost certainly want to be able to bind both propositions and regular types in a do block, but this generalization won't give you that

Mario Carneiro (Jun 21 2022 at 00:09):

the usual trick I use to bind propositions in a do block uses pattern matching and PLift:

import Lean
open Lean

def checkPos (n : Nat) : MetaM (PLift (0 < n)) :=
  if h : 0 < n then pure h else failure

def usesProp : MetaM {n // 0 < n} := do
  let n  pure 37
  let h  checkPos n
  pure n, h

James Gallicchio (Jun 21 2022 at 04:17):

Ahh, I see


Last updated: Dec 20 2023 at 11:08 UTC