Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 78a08eb

Browse files
kim-emmergify[bot]
authored andcommitted
feat(data/mllist): monadic lazy lists (#865)
* feat(data/mllist): monadic lazy lists * oops, fix header * shove into tactic namespace * make mllist into a monad (#880) * make mllist into a monad * looks good. add `take`, and some tests * update authors * cleanup test
1 parent 44d1c7a commit 78a08eb

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

src/data/mllist.lean

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/-
2+
Copyright (c) 2018 Scott Morrison. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Author: Mario Carnerio, Keeley Hoek, Simon Hudon, Scott Morrison
5+
6+
Monadic lazy lists.
7+
8+
The inductive construction is not allowed outside of meta (indeed, we can build infinite objects).
9+
This isn't so bad, as the typical use is with the tactic monad, in any case.
10+
11+
As we're in meta anyway, we don't bother with proofs about these constructions.
12+
-/
13+
import data.option.basic
14+
universes u v
15+
16+
namespace tactic -- We hide this away in the tactic namespace, just because it's all meta.
17+
18+
meta inductive mllist (m : Type u → Type u) (α : Type u) : Type u
19+
| nil {} : mllist
20+
| cons : m (option α × mllist) → mllist
21+
22+
namespace mllist
23+
24+
variables {m : Type u → Type u}
25+
26+
meta def fix {m : Type u → Type u} [alternative m]
27+
{α} (f : α → m α) : α → mllist m α
28+
| x := cons $ (λ a, (some x, fix a)) <$> f x <|> pure (some x, nil)
29+
30+
variables [monad m]
31+
32+
meta def uncons {α : Type u} : mllist m α → m (option (α × mllist m α))
33+
| nil := pure none
34+
| (cons l) := do (x,xs) ← l,
35+
some x ← return x | uncons xs,
36+
return (x,xs)
37+
38+
meta def empty {α : Type u} (xs : mllist m α) : m (ulift bool) :=
39+
(ulift.up ∘ option.is_some) <$> uncons xs
40+
41+
meta def of_list {α : Type u} : list α → mllist m α
42+
| [] := nil
43+
| (h :: t) := cons (pure (h, of_list t))
44+
45+
meta def m_of_list {α : Type u} : list (m α) → mllist m α
46+
| [] := nil
47+
| (h :: t) := cons ((λ x, (x, m_of_list t)) <$> some <$> h)
48+
49+
meta def force {α} : mllist m α → m (list α)
50+
| nil := pure []
51+
| (cons l) :=
52+
do (x,xs) ← l,
53+
some x ← pure x | force xs,
54+
(::) x <$> (force xs)
55+
56+
meta def take {α} : mllist m α → ℕ → m (list α)
57+
| nil _ := pure []
58+
| _ 0 := pure []
59+
| (cons l) (n+1) :=
60+
do (x,xs) ← l,
61+
some x ← pure x | take xs n,
62+
(::) x <$> (take xs n)
63+
64+
meta def map {α β : Type u} (f : α → β) : mllist m α → mllist m β
65+
| nil := nil
66+
| (cons l) := cons $ do (x,xs) ← l, pure (f <$> x, map xs)
67+
68+
meta def mmap {α β : Type u} (f : α → m β) : mllist m α → mllist m β
69+
| nil := nil
70+
| (cons l) :=
71+
cons $ do (x,xs) ← l,
72+
b ← x.traverse f,
73+
return (b, mmap xs)
74+
75+
meta def filter {α : Type u} (p : α → Prop) [decidable_pred p] : mllist m α → mllist m α
76+
| nil := nil
77+
| (cons l) :=
78+
cons $ do (a,r) ← l ,
79+
some a ← return a | return (none, filter r),
80+
return (if p a then some a else none, filter r)
81+
82+
meta def mfilter [alternative m] {α β : Type u} (p : α → m β) : mllist m α → mllist m α
83+
| nil := nil
84+
| (cons l) :=
85+
cons $ do (a,r) ← l,
86+
some a ← return a | return (none, mfilter r),
87+
(p a >> return (a, mfilter r)) <|> return (none , mfilter r)
88+
89+
meta def filter_map {α β : Type u} (f : α → option β) : mllist m α → mllist m β
90+
| nil := nil
91+
| (cons l) :=
92+
cons $ do (a,r) ← l,
93+
some a ← return a | return (none, filter_map r),
94+
match f a with
95+
| (some b) := return (some b, filter_map r)
96+
| none := return (none, filter_map r)
97+
end
98+
99+
meta def mfilter_map [alternative m] {α β : Type u} (f : α → m β) : mllist m α → mllist m β
100+
| nil := nil
101+
| (cons l) :=
102+
cons $ do (a,r) ← l,
103+
some a ← return a | return (none, mfilter_map r),
104+
(f a >>= (λ b, return (some b, mfilter_map r))) <|> return (none, mfilter_map r)
105+
106+
meta def append {α : Type u} : mllist m α → mllist m α → mllist m α
107+
| nil ys := ys
108+
| (cons xs) ys :=
109+
cons $ do (x,xs) ← xs,
110+
return (x, append xs ys)
111+
112+
meta def join {α : Type u} : mllist m (mllist m α) → mllist m α
113+
| nil := nil
114+
| (cons l) :=
115+
cons $ do (xs,r) ← l,
116+
some xs ← return xs | return (none, join r),
117+
match xs with
118+
| nil := return (none, join r)
119+
| cons m := do (a,n) ← m, return (a, join (cons $ return (n, r)))
120+
end
121+
122+
meta def enum_from {α : Type u} : ℕ → mllist m α → mllist m (ℕ × α)
123+
| _ nil := nil
124+
| n (cons l) :=
125+
cons $ do (a,r) ← l,
126+
some a ← return a | return (none, enum_from n r),
127+
return ((n, a), (enum_from (n + 1) r))
128+
129+
meta def enum {α : Type u} : mllist m α → mllist m (ℕ × α) := enum_from 0
130+
131+
meta def concat {α : Type u} : mllist m α → α → mllist m α
132+
| L a := (mllist.of_list [L, mllist.of_list [a]]).join
133+
134+
meta def bind_ {α β : Type u} : mllist m α → (α → mllist m β) → mllist m β
135+
| nil f := nil
136+
| (cons ll) f :=
137+
cons $ do (x,xs) ← ll,
138+
some x ← return x | return (none, bind_ xs f),
139+
return (none, append (f x) (bind_ xs f))
140+
141+
meta def monad_lift {α} (x : m α) : mllist m α := cons $ (flip prod.mk nil ∘ some) <$> x
142+
143+
end mllist
144+
145+
end tactic

test/mllist.lean

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import data.mllist
2+
3+
@[reducible] def S (α : Type) := state_t (list nat) option α
4+
def append (x : nat) : S unit :=
5+
{ run := λ s, some ((), x :: s) }
6+
7+
def F : nat → S nat
8+
| 0 := failure
9+
| (n+1) := append (n+1) >> pure n
10+
11+
open tactic
12+
13+
run_cmd
14+
(do let x := ((mllist.fix F 10).force).run [],
15+
guard $ x = (some ([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])))
16+
run_cmd
17+
(do let x := (((mllist.fix F 10).map(λ n, n*n)).take 2).run [],
18+
guard $ x = (some ([100, 81], [9, 10])))
19+
run_cmd
20+
(do let x := (((mllist.fix F 10).mmap(λ n, pure $ n*n)).take 3).run [],
21+
guard $ x = (some ([100, 81, 64], [8, 9, 10])))
22+
23+
meta def l1 : mllist S nat := mllist.of_list [0,1,2]
24+
meta def l2 : mllist S nat := mllist.of_list [3,4,5]
25+
meta def ll : mllist S nat := (mllist.of_list [l1, l2]).join
26+
27+
run_cmd
28+
(do let x := ll.force.run [],
29+
guard $ x = (some ([0, 1, 2, 3, 4, 5], [])))

0 commit comments

Comments
 (0)