Zulip Chat Archive
Stream: lean4
Topic: Seq.seq on an Option
Chris Lovett (Aug 24 2022 at 03:05):
can someone give me a simple example of implementing Seq.seq on an Option? I'm a bit surprised the while Option is a Monad (instance : Monad Option where...
), seq does not seem to be defined:
Mario Carneiro (Aug 24 2022 at 03:05):
seq
is not an exported name, you have to use Seq.seq
Mario Carneiro (Aug 24 2022 at 03:05):
or <*>
Chris Lovett (Aug 24 2022 at 03:06):
Ha, but pure is ?
def fred : Option Nat :=
pure 5
#eval fred -- some 5
Mario Carneiro (Aug 24 2022 at 03:06):
yes
Mario Carneiro (Aug 24 2022 at 03:06):
if you look in the prelude file you will find export Pure (pure)
Mario Carneiro (Aug 24 2022 at 03:07):
which basically means it's open
for everyone
Mario Carneiro (Aug 24 2022 at 03:07):
This has nothing to do with Option
or the way the monad is defined BTW
Mario Carneiro (Aug 24 2022 at 03:09):
if you are wondering why src4#instMonadOption does not declare a seq
field, it's because there is a default implementation of seq
in terms of bind
and map
in src4#Monad
Chris Lovett (Aug 24 2022 at 03:10):
So where is the seq defined for Option? I see the type class:
class Seq (f : Type u → Type v) : Type (max (u+1) v) where
seq : {α β : Type u} → f (α → β) → (Unit → f α) → f β
But when the Option Monad instance is defined there is no seq := ...
filling in the Option specific implementation so what happens?
Chris Lovett (Aug 24 2022 at 03:10):
Ah thanks you just answered my question...
Chris Lovett (Aug 24 2022 at 03:18):
So how would I port something like this from Haskell using Option instead of Maybe:
pure (*) <*> Just 4 <*> Just 5 -- Just 20
Chris Lovett (Aug 24 2022 at 03:25):
Never mind, I got it:
#eval pure Mul.mul <*> some 4 <*> some 5
Leonardo de Moura (Aug 24 2022 at 03:25):
#eval pure (·*·) <*> some 4 <*> some 5 -- some 20
#eval pure (.*.) <*> some 4 <*> some 5 -- some 20
Leonardo de Moura (Aug 24 2022 at 03:28):
For more information about the (·*·)
. https://leanprover.github.io/functional_programming_in_lean/getting-to-know/conveniences.html#anonymous-functions
Leonardo de Moura (Aug 24 2022 at 03:29):
https://leanprover.github.io/lean4/doc/functions.html#syntax-sugar-for-simple-lambda-expressions
Chris Lovett (Aug 24 2022 at 03:32):
Yep thanks, I remember (. * .) from that chapter.
Mario Carneiro (Aug 24 2022 at 03:56):
Usually, we would use <$>
for the first application there to avoid the pure
Mario Carneiro (Aug 24 2022 at 03:56):
#eval (.*.) <$> some 4 <*> some 5 -- some 20
Chris Lovett (Aug 24 2022 at 03:58):
Oh, much nicer, thanks! I was pretty confused about using pure
on a function (.*.)
...
Chris Lovett (Aug 24 2022 at 04:25):
Looking at seq f x := bind f fun y => Functor.map y (x ())
why does x
take () as input, making my example more combersome:
#eval Seq.seq ((.*.) <$> (some 4)) (fun _ : Unit => (some 5)) -- some 20
only to have the infix notation invent that required function:
@[inheritDoc] notation:60 a:60 " <*> " b:61 => Seq.seq a fun _ : Unit => b
so I can write the lovely clean:
#eval pure (·*·) <*> some 4 <*> some 5
?
Mario Carneiro (Aug 24 2022 at 04:26):
Because lean is an eagerly evaluated language (call-by-value), you have to use Unit ->
functions whenever you want to explicitly delay evaluation
Mario Carneiro (Aug 24 2022 at 04:27):
So the idea here is that we want f <*> long_running x
to not evaluate long_running x
unless the evaluation of seq
determines that it is necessary
Mario Carneiro (Aug 24 2022 at 04:27):
For example, if we are working over Option
, we want none <*> some (long_running x)
to not evaluate long_running x
at all
Chris Lovett (Aug 24 2022 at 04:30):
Interesting thanks.
Chris Lovett (Aug 24 2022 at 04:41):
Stuck on the next sample following the same pattern, this time on List:
#eval (.*.) <$> [1, 2, 3] <*> [4, 5, 6] -- failed to synthesize instance Seq List
Mario Carneiro (Aug 24 2022 at 04:42):
There is (currently) no Monad List
instance. You will have to provide one yourself if you want to use it in examples
Mario Carneiro (Aug 24 2022 at 04:43):
see https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/List.20Functor
Chris Lovett (Aug 24 2022 at 19:15):
Hey this stuff is very slowly starting to make sense... I got the sample from mmhaskell working using this:
instance : Applicative List where
pure := List.pure
seq f x := List.bind f fun y => Functor.map y (x ())
#eval [(· +2), (· *3)] <*> [4, 6] -- [6, 8, 12, 18]
Mario Carneiro (Aug 24 2022 at 19:25):
It's presumably easier to just make an instance of Monad List
using List.bind
and List.pure
and then the seq
will get automatically filled in
Chris Lovett (Aug 24 2022 at 21:44):
True but then the chapter is jumping ahead to monads... it is supposed to be building up to Monads :-) But it's tempting - especially since it avoids the awkward delayed function execution trick with x ()
.
Chris Lovett (Aug 24 2022 at 21:46):
Does Lean Applicative obey the Interchange law:
-- Interchange
u <*> pure y = pure ($ y) <*> u
if so now do I write an example of this using my applicative list or Option ? I'm not sure what the Haskell syntax $ y
means... and I'm not sure our <*>
can put the function u
on the right hand side like this can it?
Chris Lovett (Aug 24 2022 at 22:09):
Perhaps this is an example of interchange?
#eval pure (·+·) <*> [1, 2] <*> [3, 4] -- [4, 5, 5, 6]
#eval pure (·+·) <*> [3, 4] <*> [1, 2] -- [4, 5, 5, 6]
Mario Carneiro (Aug 24 2022 at 23:16):
Does Lean Applicative obey the Interchange law
No. Lean's Applicative
doesn't obey any laws, really (that's what LawfulApplicative
et al are for), but even then we do not generally assume this property for lawful applicatives. Applicatives that do have this property are called commutative IIRC
Mario Carneiro (Aug 24 2022 at 23:17):
and List
is not commutative
Mario Carneiro (Aug 24 2022 at 23:17):
The haskell syntax ($ y)
is equivalent to (. y)
in lean, i.e. fun f => f y
Mario Carneiro (Aug 24 2022 at 23:19):
Option
is commutative, as is Multiset
( = List
quotient by permutation)
Mario Carneiro (Aug 24 2022 at 23:30):
Actually I take it back. The interchange law takes one side or the other to be a pure
, in which case it is true for any lawful applicative because both sides are equivalent to the map
expression (· y) <$> u
Mario Carneiro (Aug 24 2022 at 23:30):
example [Applicative m] [LawfulApplicative m] (u : m (α → β)) (y : α) :
u <*> pure y = pure (· y) <*> u := by simp [pure_seq]
Mario Carneiro (Aug 24 2022 at 23:36):
Commutativity for applicatives says you can reorder effects, like this:
class CommApplicative (m) [Applicative m] where
comm (x : m (α → β)) (y : m α) : x <*> y = flip id <$> y <*> x
Chris Lovett (Aug 24 2022 at 23:52):
Should we add this to LawfulApplicative ?
Reid Barton (Aug 24 2022 at 23:58):
No, this is an additional property which usually does not hold
Last updated: Dec 20 2023 at 11:08 UTC