From f5e2db760e42570bb412e1a93b32cb1b796a3d4f Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Thu, 4 Jul 2019 19:40:26 +0200
Subject: [PATCH] Make the `list` stuff simpler since we don't really use
 `val_encode` anymore.

---
 _CoqProject                                   |   1 -
 {theories/utils => experimental}/encodable.v  |   0
 .../producer_consumer.v                       |   9 +-
 theories/channel/channel.v                    |   4 +-
 theories/examples/mapper.v                    |  17 +-
 theories/examples/sort.v                      |  32 +--
 theories/examples/sort_client.v               |  16 +-
 theories/examples/sort_elem_client.v          |  10 +-
 theories/utils/list.v                         | 222 ++++++------------
 9 files changed, 117 insertions(+), 194 deletions(-)
 rename {theories/utils => experimental}/encodable.v (100%)
 rename {theories/examples => experimental}/producer_consumer.v (95%)

diff --git a/_CoqProject b/_CoqProject
index 0116ae5..7961f39 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -1,7 +1,6 @@
 -Q theories osiris
 -arg -w -arg -notation-overridden,-redundant-canonical-projection,-several-object-files
 theories/utils/auth_excl.v
-theories/utils/encodable.v
 theories/utils/list.v
 theories/utils/compare.v
 theories/utils/spin_lock.v
diff --git a/theories/utils/encodable.v b/experimental/encodable.v
similarity index 100%
rename from theories/utils/encodable.v
rename to experimental/encodable.v
diff --git a/theories/examples/producer_consumer.v b/experimental/producer_consumer.v
similarity index 95%
rename from theories/examples/producer_consumer.v
rename to experimental/producer_consumer.v
index e0efb05..ed3d4d8 100644
--- a/theories/examples/producer_consumer.v
+++ b/experimental/producer_consumer.v
@@ -4,10 +4,8 @@ From iris.heap_lang Require Import proofmode notation.
 From iris.heap_lang Require Import assert.
 From osiris.utils Require Import list compare spin_lock.
 
-Definition qnew : val := λ: <>, #().
 Definition qenqueue : val := λ: "q" "v", #().
 Definition qdequeue : val := λ: "q", #().
-Definition qis_empty : val := λ: "q", #().
 
 Definition enq := true.
 Definition deq := false.
@@ -23,10 +21,11 @@ Definition pd_loop : val :=
     if: "cc" ≤ #0 then #() else 
     if: recv "c" then (* enq/deq *)
       if: recv "c" then (* cont/stop *)
-        "go" (qenqueue "q" (recv "c")) "pc" "cc" "c"
+        let: "x" := recv "x" in
+        "go" (qenqueue "q" "x") "pc" "cc" "c"
       else "go" "q" ("pc"-#1) "cc" "c"
     else
-      if: (qis_empty "q") then
+      if: lisnil "q" then
         if: "pc" ≤ #0 then
           send "c" #stop;;
           "go" "q" "pc" ("cc"-#1) "c"
@@ -40,7 +39,7 @@ Definition pd_loop : val :=
         "go" (Fst "qv") "pc" "cc" "c".
 
 Definition new_pd : val := λ: "pc" "cc",
-  let: "q" := qnew #() in
+  let: "q" := lnil #() in
   let: "c" := start_chan (λ: "c", pd_loop "q" "pc" "cc" "c") in
   let: "l" := new_lock #() in
   ("c", "l").
diff --git a/theories/channel/channel.v b/theories/channel/channel.v
index a6acf89..c2e7096 100644
--- a/theories/channel/channel.v
+++ b/theories/channel/channel.v
@@ -56,7 +56,7 @@ Section channel.
   Context `{!heapG Σ, !chanG Σ} (N : namespace).
 
   Definition is_list_ref (l : val) (xs : list val) : iProp Σ :=
-    (∃ l' : loc, ⌜l = #l'⌝ ∧ l' ↦ val_encode xs)%I.
+    (∃ l' : loc, ⌜l = #l'⌝ ∧ l' ↦ llist xs)%I.
 
   Record chan_name := Chan_name {
     chan_lock_name : gname;
@@ -139,7 +139,7 @@ Section channel.
       (vs ws) "(Href & Hvs & Href' & Hws)".
     iDestruct "Href" as (ll Hslr) "Hll". rewrite Hslr.
     wp_load.
-    wp_apply (lsnoc_spec (A:=val))=> //; iIntros (_).
+    wp_apply (lsnoc_spec with "[//]"); iIntros (_).
     wp_bind (_ <- _)%E.
     iMod "HΦ" as (vs') "[Hchan HΦ]".
     iDestruct (excl_eq with "Hvs Hchan") as %<-%leibniz_equiv.
diff --git a/theories/examples/mapper.v b/theories/examples/mapper.v
index 411d385..c3b3c96 100644
--- a/theories/examples/mapper.v
+++ b/theories/examples/mapper.v
@@ -140,8 +140,8 @@ Section mapper.
       c ↣ mapper_protocol n (X_send : gmultiset A) @ N ∗
       ([∗ list] x;v ∈ xs;vs, IA x v) ∗ ([∗ list] x;w ∈ xs_recv;ws, IB (f x) w)
     }}}
-      mapper_service_loop #n c (val_encode vs) (val_encode ws)
-    {{{ ys ws, RET (val_encode ws);
+      mapper_service_loop #n c (llist vs) (llist ws)
+    {{{ ys ws, RET (llist ws);
        ⌜ys ≡ₚ f <$> elements X_send ++ xs⌝ ∗
        [∗ list] y;w ∈ ys ++ (f <$> xs_recv);ws, IB y w
     }}}.
@@ -152,20 +152,20 @@ Section mapper.
     { destruct Hn as [-> ->]; first lia.
       iApply ("HΦ" $! []); simpl. rewrite big_sepL2_fmap_l. auto. }
     destruct n as [|n]=> //=. wp_branch as %?|%_; wp_pures.
-    - wp_apply (lisnil_spec (A:=val) with "[//]"); iIntros (_).
+    - wp_apply (lisnil_spec with "[//]"); iIntros (_).
       destruct vs as [|v vs], xs as [|x xs]; csimpl; try done; wp_pures.
       + wp_select. wp_pures. rewrite Nat2Z.inj_succ Z.sub_1_r Z.pred_succ.
         iApply ("IH" with "[] Hc [//] [$] HΦ"). iPureIntro; naive_solver.
       + iDestruct "HIA" as "[HIAx HIA]". wp_select.
-        wp_apply (lhead_spec (A:=val) with "[//]"); iIntros (_).
+        wp_apply (lhead_spec with "[//]"); iIntros (_).
         wp_send with "[$HIAx]".
-        wp_apply (ltail_spec (A:=val) with "[//]"); iIntros (_).
+        wp_apply (ltail_spec with "[//]"); iIntros (_).
         wp_apply ("IH" with "[] Hc HIA HIB"); first done.
         iIntros (ys ws').
         rewrite gmultiset_elements_disj_union gmultiset_elements_singleton -!assoc_L.
         iApply "HΦ".
     - wp_recv (x w) as (HH) "HIBfx".
-      wp_apply (lcons_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (lcons_spec with "[//]"); iIntros (_).
       wp_apply ("IH" $! _ _ _ _ _ (_ :: _) with "[] Hc HIA [HIBfx HIB]"); first done.
       { simpl; iFrame. }
       iIntros (ys ws'); iDestruct 1 as (Hys) "HIB"; simplify_eq/=.
@@ -182,9 +182,8 @@ Section mapper.
     0 < n →
     (∀ x v, {{{ IA x v }}} ff v {{{ w, RET w; IB (f x) w }}}) -∗
     {{{ [∗ list] x;v ∈ xs;vs, IA x v }}}
-      mapper_service #n ff (val_encode vs)
-    {{{ ys ws, RET (val_encode ws); ⌜ys ≡ₚ f <$> xs⌝ ∗
-                                    [∗ list] y;w ∈ ys;ws, IB y w }}}.
+      mapper_service #n ff (llist vs)
+    {{{ ys ws, RET (llist ws); ⌜ys ≡ₚ f <$> xs⌝ ∗ [∗ list] y;w ∈ ys;ws, IB y w }}}.
   Proof.
     iIntros (?) "#Hf !>"; iIntros (Φ) "HI HΦ". wp_lam; wp_pures.
     wp_apply (new_lock_spec N with "[//]"); iIntros (lk) "[Hu Hlk]".
diff --git a/theories/examples/sort.v b/theories/examples/sort.v
index ce043c8..99f16b1 100644
--- a/theories/examples/sort.v
+++ b/theories/examples/sort.v
@@ -43,42 +43,42 @@ Section sort.
          `{!RelDecision R, !Total R} (cmp : val),
        MSG cmp {{ cmp_spec I R cmp }};
      <!> (xs : list A) (l : loc) (vs : list val),
-       MSG #l {{ l ↦ val_encode vs ∗ [∗ list] x;v ∈ xs;vs, I x v }};
+       MSG #l {{ l ↦ llist vs ∗ [∗ list] x;v ∈ xs;vs, I x v }};
      <?> (xs' : list A) (vs' : list val),
        MSG #() {{ ⌜ Sorted R xs' ⌝ ∗ ⌜ xs' ≡ₚ xs ⌝ ∗
-                  l ↦ val_encode vs' ∗ [∗ list] x;v ∈ xs';vs', I x v }};
+                  l ↦ llist vs' ∗ [∗ list] x;v ∈ xs';vs', I x v }};
      END)%proto.
 
   Lemma lmerge_spec {A} (I : A → val → iProp Σ) (R : A → A → Prop)
       `{!RelDecision R, !Total R} (cmp : val) xs1 xs2 vs1 vs2 :
     cmp_spec I R cmp -∗
     {{{ ([∗ list] x;v ∈ xs1;vs1, I x v) ∗ ([∗ list] x;v ∈ xs2;vs2, I x v) }}}
-      lmerge cmp (val_encode vs1) (val_encode vs2)
-    {{{ ws, RET val_encode ws; [∗ list] x;v ∈ list_merge R xs1 xs2;ws, I x v }}}.
+      lmerge cmp (llist vs1) (llist vs2)
+    {{{ ws, RET llist ws; [∗ list] x;v ∈ list_merge R xs1 xs2;ws, I x v }}}.
   Proof.
     iIntros "#Hcmp" (Ψ) "!> [HI1 HI2] HΨ". iLöb as "IH" forall (xs1 xs2 vs1 vs2 Ψ).
-    wp_lam. wp_apply (lisnil_spec (A:=val) with "[//]"); iIntros (_).
+    wp_lam. wp_apply (lisnil_spec with "[//]"); iIntros (_).
     destruct xs1 as [|x1 xs1], vs1 as [|v1 vs1]; simpl; done || wp_pures.
     { iApply "HΨ". by rewrite list_merge_nil_l. }
-    wp_apply (lisnil_spec (A:=val) with "[//]"); iIntros (_).
+    wp_apply (lisnil_spec with "[//]"); iIntros (_).
     destruct xs2 as [|x2 xs2], vs2 as [|v2 vs2]; simpl; done || wp_pures.
     { iApply "HΨ". iFrame. }
-    wp_apply (lhead_spec (A:=val) with "[//]"); iIntros (_).
-    wp_apply (lhead_spec (A:=val) with "[//]"); iIntros (_).
+    wp_apply (lhead_spec with "[//]"); iIntros (_).
+    wp_apply (lhead_spec with "[//]"); iIntros (_).
     iDestruct "HI1" as "[HI1 HI1']"; iDestruct "HI2" as "[HI2 HI2']".
     wp_apply ("Hcmp" with "[$HI1 $HI2]"); iIntros "[HI1 HI2]".
     case_bool_decide; wp_pures.
     - rewrite decide_True //.
-      wp_apply (ltail_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (ltail_spec with "[//]"); iIntros (_).
       wp_apply ("IH" $! _ (x2 :: _) with "HI1'[HI2 HI2']"); [simpl; iFrame|].
       iIntros (ws) "HI".
-      wp_apply (lcons_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (lcons_spec with "[//]"); iIntros (_).
       iApply "HΨ". iFrame.
     - rewrite decide_False //.
-      wp_apply (ltail_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (ltail_spec with "[//]"); iIntros (_).
       wp_apply ("IH" $! (x1 :: _) with "[HI1 HI1'] HI2'"); [simpl; iFrame|].
       iIntros (ws) "HI".
-      wp_apply (lcons_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (lcons_spec with "[//]"); iIntros (_).
       iApply "HΨ". iFrame.
   Qed.
 
@@ -91,13 +91,13 @@ Section sort.
     wp_lam.
     wp_recv (A I R ?? cmp) as "#Hcmp".
     wp_recv (xs l vs) as "[Hl HI]".
-    wp_load. wp_apply (llength_spec (A:=val) with "[//]"); iIntros (_).
+    wp_load. wp_apply (llength_spec with "[//]"); iIntros (_).
     iDestruct (big_sepL2_length with "HI") as %<-.
     wp_op; case_bool_decide as Hlen; wp_if.
     { assert (Sorted R xs).
       { destruct xs as [|x1 [|x2 xs]]; simpl in *; eauto with lia. }
       wp_send with "[$Hl $HI]"; first by auto. by iApply "HΨ". }
-    wp_load. wp_apply (lsplit_spec (A:=val) with "[//]"); iIntros (vs1 vs2 <-).
+    wp_load. wp_apply (lsplit_spec with "[//]"); iIntros (vs1 vs2 ->).
     wp_alloc l1 as "Hl1"; wp_alloc l2 as "Hl2".
     iDestruct (big_sepL2_app_inv_r with "HI") as (xs1 xs2 ->) "[HI1 HI2]".
     wp_apply (start_chan_proto_spec N sort_protocol); iIntros (cy) "Hcy".
@@ -125,10 +125,10 @@ Section sort.
   Lemma sort_client_spec {A} (I : A → val → iProp Σ) R
        `{!RelDecision R, !Total R} cmp l (vs : list val) (xs : list A) :
     cmp_spec I R cmp -∗
-    {{{ l ↦ val_encode vs ∗ [∗ list] x;v ∈ xs;vs, I x v }}}
+    {{{ l ↦ llist vs ∗ [∗ list] x;v ∈ xs;vs, I x v }}}
       sort_client cmp #l
     {{{ ys ws, RET #(); ⌜Sorted R ys⌝ ∗ ⌜ys ≡ₚ xs⌝ ∗
-               l ↦ val_encode ws ∗ [∗ list] y;w ∈ ys;ws, I y w }}}.
+               l ↦ llist ws ∗ [∗ list] y;w ∈ ys;ws, I y w }}}.
   Proof.
     iIntros "#Hcmp !>" (Φ) "Hl HΦ". wp_lam.
     wp_apply (start_chan_proto_spec N sort_protocol); iIntros (c) "Hc".
diff --git a/theories/examples/sort_client.v b/theories/examples/sort_client.v
index e52de6d..49416b6 100644
--- a/theories/examples/sort_client.v
+++ b/theories/examples/sort_client.v
@@ -7,27 +7,21 @@ From osiris.examples Require Import sort.
 Section sort_client.
   Context `{!heapG Σ, !proto_chanG Σ} (N : namespace).
 
-  Local Arguments val_encode _ _ !_ /.
-
   Lemma sort_client_le_spec l (xs : list Z) :
-    {{{ l ↦ val_encode xs }}}
+    {{{ l ↦ llist (LitV ∘ LitInt <$> xs) }}}
       sort_client cmpZ #l
-    {{{ ys, RET #(); ⌜Sorted (≤) ys⌝ ∗ ⌜ ys ≡ₚ xs⌝ ∗ l ↦ val_encode ys }}}.
+    {{{ ys, RET #(); ⌜Sorted (≤) ys⌝ ∗ ⌜ ys ≡ₚ xs⌝ ∗ l ↦ llist (LitV ∘ LitInt <$> ys) }}}.
   Proof.
-    assert (∀ zs : list Z, val_encode zs = val_encode (LitV ∘ LitInt <$> zs)) as Henc.
-    { intros zs. induction zs; f_equal/=; auto with f_equal. }
     iIntros (Φ) "Hl HΦ".
     iApply (sort_client_spec N IZ (≤) _ _ (LitV ∘ LitInt <$> xs) xs with "[] [Hl] [HΦ]").
     { iApply cmpZ_spec. }
-    { rewrite -Henc. iFrame "Hl".
-      iInduction xs as [|x xs] "IH"; csimpl; first by iFrame.
-      by iFrame "IH". }
+    { iFrame "Hl". iInduction xs as [|x xs] "IH"; csimpl; by iFrame "#". }
     iIntros "!>" (ys ws) "(?&?&?&HI)".
     iAssert ⌜ ws = (LitV ∘ LitInt) <$> ys ⌝%I with "[HI]" as %->.
     { iInduction ys as [|y ys] "IH" forall (ws);
-      destruct ws as [|w ws]; csimpl; try done.
+        destruct ws as [|w ws]; csimpl; try done.
       iDestruct "HI" as "[-> HI2]".
       by iDestruct ("IH" with "HI2") as %->. }
-    rewrite -Henc. iApply ("HΦ" $! ys with "[$]").
+    iApply ("HΦ" $! ys with "[$]").
   Qed.
 End sort_client.
diff --git a/theories/examples/sort_elem_client.v b/theories/examples/sort_elem_client.v
index 28f384c..073f59e 100644
--- a/theories/examples/sort_elem_client.v
+++ b/theories/examples/sort_elem_client.v
@@ -31,7 +31,7 @@ Section sort_elem_client.
 
   Lemma send_all_spec c p xs' xs vs :
     {{{ c ↣ sort_elem_head_protocol I R xs' <++> p @ N ∗ [∗ list] x;v ∈ xs;vs, I x v }}}
-      send_all c (val_encode vs)
+      send_all c (llist vs)
     {{{ RET #(); c ↣ sort_elem_tail_protocol I R (xs' ++ xs) [] <++> p @ N }}}.
   Proof.
     iIntros (Φ) "[Hc HI] HΦ".
@@ -46,7 +46,7 @@ Section sort_elem_client.
     Sorted R ys' →
     {{{ c ↣ sort_elem_tail_protocol I R xs ys' <++> p @ N }}}
       recv_all c
-    {{{ ys ws, RET (val_encode ws);
+    {{{ ys ws, RET (llist ws);
         ⌜Sorted R (ys' ++ ys)⌝ ∗ ⌜ys' ++ ys ≡ₚ xs⌝ ∗
         c ↣ p @ N ∗ [∗ list] y;w ∈ ys;ws, I y w
     }}}.
@@ -57,7 +57,7 @@ Section sort_elem_client.
     - wp_recv (y v) as (Htl) "HIxv".
       wp_apply ("IH" with "[] Hc"); first by auto using Sorted_snoc.
       iIntros (ys ws). rewrite -!assoc_L. iDestruct 1 as (??) "[Hc HI]".
-      wp_apply (lcons_spec (A:=val) with "[//]"); iIntros (_).
+      wp_apply (lcons_spec with "[//]"); iIntros (_).
       iApply ("HΦ" $! (y :: ys)). simpl; iFrame; auto.
     - wp_apply (lnil_spec with "[//]"); iIntros (_).
       iApply ("HΦ" $! [] []); rewrite /= right_id_L; by iFrame.
@@ -66,8 +66,8 @@ Section sort_elem_client.
   Lemma sort_client_spec cmp vs xs :
     cmp_spec I R cmp -∗
     {{{ [∗ list] x;v ∈ xs;vs, I x v }}}
-      sort_elem_client cmp (val_encode vs)
-    {{{ ys ws, RET (val_encode ws); ⌜Sorted R ys⌝ ∗ ⌜ys ≡ₚ xs⌝ ∗
+      sort_elem_client cmp (llist vs)
+    {{{ ys ws, RET (llist ws); ⌜Sorted R ys⌝ ∗ ⌜ys ≡ₚ xs⌝ ∗
                [∗ list] y;w ∈ ys;ws, I y w }}}.
   Proof.
     iIntros "#Hcmp !>" (Φ) "HI HΦ". wp_lam.
diff --git a/theories/utils/list.v b/theories/utils/list.v
index 4d0702e..1767faa 100644
--- a/theories/utils/list.v
+++ b/theories/utils/list.v
@@ -1,15 +1,13 @@
 From iris.heap_lang Require Export proofmode notation.
 From iris.heap_lang Require Import assert.
-From osiris.utils Require Export encodable.
 
 (** Immutable ML-style functional lists *)
-Instance list_val_enc `{ValEnc A} : ValEnc (list A) :=
-  fix go xs :=
-  let _ : ValEnc _ := @go in
-  match xs with
-  | [] => val_encode None
-  | x :: xs => val_encode (Some (x,xs))
-  end.
+Fixpoint llist (vs : list val) : val :=
+  match vs with
+  | [] => NONEV
+  | v :: vs => SOMEV (v,llist vs)
+  end%V.
+Arguments llist : simpl never.
 
 Definition lnil : val := λ: <>, NONEV.
 Definition lcons : val := λ: "x" "l", SOME ("x", "l").
@@ -49,15 +47,6 @@ Definition lreplicate : val :=
     if: "n" = #0 then lnil #() else
     let: "l" := "go" ("n" - #1) "x" in lcons "x" "l".
 
-Definition llist_member : val :=
-  rec: "go" "x" "l" :=
-    match: "l" with
-      NONE => #false
-    | SOME "p" =>
-      if: Fst "p" = "x" then #true
-      else let: "l" := (Snd "p")  in "go" "x" "l"
-    end.
-
 Definition llength : val :=
   rec: "go" "l" :=
     match: "l" with
@@ -97,195 +86,138 @@ Definition lsplit : val :=
   λ: "l", lsplit_at "l" ((llength "l") `quot` #2).
 
 Section lists.
-Context `{heapG Σ} `{ValEncDec A}.
+Context `{heapG Σ}.
 Implicit Types i : nat.
-Implicit Types x : A.
-Implicit Types xs : list A.
+Implicit Types v : val.
+Implicit Types vs : list val.
 
 Lemma lnil_spec :
-  {{{ True }}} lnil #() {{{ RET val_encode []; True }}}.
+  {{{ True }}} lnil #() {{{ RET llist []; True }}}.
 Proof. iIntros (Φ _) "HΦ". wp_lam. by iApply "HΦ". Qed.
 
-Lemma lcons_spec x xs :
-  {{{ True }}}
-    lcons (val_encode x) (val_encode xs)
-  {{{ RET val_encode (x :: xs); True }}}.
+Lemma lcons_spec v vs :
+  {{{ True }}} lcons v (llist vs) {{{ RET llist (v :: vs); True }}}.
 Proof. iIntros (Φ _) "HΦ". wp_lam. wp_pures. by iApply "HΦ". Qed.
 
-Lemma lisnil_spec xs:
+Lemma lisnil_spec vs:
   {{{ True }}}
-    lisnil (val_encode xs)
-  {{{ RET #(if xs is [] then true else false); True }}}.
-Proof. iIntros (Φ _) "HΦ". wp_lam. destruct xs; wp_pures; by iApply "HΦ". Qed.
+    lisnil (llist vs)
+  {{{ RET #(if vs is [] then true else false); True }}}.
+Proof. iIntros (Φ _) "HΦ". wp_lam. destruct vs; wp_pures; by iApply "HΦ". Qed.
 
-Lemma lhead_spec x xs:
-  {{{ True }}} lhead (val_encode (x::xs)) {{{ RET val_encode x; True }}}.
+Lemma lhead_spec v vs :
+  {{{ True }}} lhead (llist (v :: vs)) {{{ RET v; True }}}.
 Proof. iIntros (Φ _) "HΦ". wp_lam. wp_pures. by iApply "HΦ". Qed.
 
-Lemma ltail_spec x xs :
-  {{{ True }}} ltail (val_encode (x::xs)) {{{ RET val_encode xs; True }}}.
+Lemma ltail_spec v vs :
+  {{{ True }}} ltail (llist (v :: vs)) {{{ RET llist vs; True }}}.
 Proof. iIntros (Φ _) "HΦ". wp_lam. wp_pures. by iApply "HΦ". Qed.
 
-Lemma llookup_spec i xs x:
-  xs !! i = Some x →
-  {{{ True }}}
-    llookup #i (val_encode xs)
-  {{{ RET val_encode x; True }}}.
+Lemma llookup_spec i vs v :
+  vs !! i = Some v →
+  {{{ True }}} llookup #i (llist vs) {{{ RET v; True }}}.
 Proof.
-  iIntros (Hi Φ Hl) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (i Hi Hl);
+  iIntros (Hi Φ _) "HΦ".
+  iInduction vs as [|v' vs] "IH" forall (i Hi);
     destruct i as [|i]=> //; simplify_eq/=.
   { wp_lam. wp_pures. by iApply (lhead_spec with "[//]"). }
   wp_lam. wp_pures.
-  wp_apply (ltail_spec with "[//]"); iIntros (?). wp_let.
+  wp_apply (ltail_spec with "[//]"); iIntros (_). wp_let.
   wp_op. rewrite Nat2Z.inj_succ -Z.add_1_l Z.add_simpl_l. by iApply "IH".
 Qed.
 
-Lemma linsert_spec i xs x :
-  is_Some (xs !! i) →
-  {{{ True }}}
-    linsert #i (val_encode x) (val_encode xs)
-  {{{ RET val_encode (<[i:=x]>xs); True }}}.
+Lemma linsert_spec i vs v :
+  is_Some (vs !! i) →
+  {{{ True }}} linsert #i v (llist vs) {{{ RET llist (<[i:=v]>vs); True }}}.
 Proof.
-  iIntros ([w Hi] Φ Hl) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (i Hi Hl Φ);
+  iIntros ([w Hi] Φ _) "HΦ".
+  iInduction vs as [|v' vs] "IH" forall (i Hi Φ);
     destruct i as [|i]=> //; simplify_eq/=.
-  { wp_lam. wp_pures. wp_apply (ltail_spec with "[//]"). iIntros (?).
+  { wp_lam. wp_pures. wp_apply (ltail_spec with "[//]"); iIntros (_).
     wp_let. by iApply (lcons_spec with "[//]"). }
   wp_lam; wp_pures.
-  wp_apply (ltail_spec with "[//]"); iIntros (?). wp_let.
+  wp_apply (ltail_spec with "[//]"); iIntros (_). wp_let.
   wp_op. rewrite Nat2Z.inj_succ -Z.add_1_l Z.add_simpl_l.
-  wp_apply ("IH" with "[//] [//]"). iIntros (?). wp_let.
+  wp_apply ("IH" with "[//]"); iIntros (_).
   wp_apply (lhead_spec with "[//]"); iIntros "_".
   by wp_apply (lcons_spec with "[//]").
 Qed.
 
-(*
-Lemma llist_member_spec `{EqDecision A} (xs : list A) (x : A) :
-  {{{ True }}}
-    llist_member (val_encode x) (val_encode xs)
-  {{{ RET #(bool_decide (x ∈ xs)); True }}}.
-Proof.
-  iIntros (Φ Hl) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (Hl); simplify_eq/=.
-  { wp_lam; wp_pures. by iApply "HΦ". }
-  wp_lam; wp_pures.
-  destruct (bool_decide_reflect (val_encode x' = val_encode x)); simplify_eq/=; wp_if.
-  { rewrite (bool_decide_true (_ ∈ _ :: _)); last by left. by iApply "HΦ". }
-  wp_proj. wp_let. iApply ("IH" with "[//]").
-  destruct (bool_decide_reflect (x ∈ xs)).
-  - by rewrite bool_decide_true; last by right.
-  - by rewrite bool_decide_false ?elem_of_cons; last naive_solver.
-Qed.
-*)
-
-Lemma lreplicate_spec i x :
-  {{{ True }}}
-    lreplicate #i (val_encode x)
-  {{{ RET val_encode (replicate i x); True }}}.
+Lemma lreplicate_spec i v :
+  {{{ True }}} lreplicate #i v {{{ RET llist (replicate i v); True }}}.
 Proof.
   iIntros (Φ _) "HΦ". iInduction i as [|i] "IH" forall (Φ); simpl.
-  { wp_lam; wp_pures.
-    iApply (lnil_spec with "[//]"). iApply "HΦ". }
+  { wp_lam; wp_pures. iApply (lnil_spec with "[//]"); auto. }
   wp_lam; wp_pures.
   rewrite Nat2Z.inj_succ -Z.add_1_l Z.add_simpl_l.
-  wp_apply "IH"; iIntros (Hl). wp_let. by iApply (lcons_spec with "[//]").
+  wp_apply "IH"; iIntros (_). wp_let. by iApply (lcons_spec with "[//]").
 Qed.
 
-Lemma llength_spec xs :
-  {{{ True }}} llength (val_encode xs) {{{ RET #(length xs); True }}}.
+Lemma llength_spec vs :
+  {{{ True }}} llength (llist vs) {{{ RET #(length vs); True }}}.
 Proof.
-  iIntros (Φ Hl) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (Hl Φ); simplify_eq/=.
+  iIntros (Φ _) "HΦ".
+  iInduction vs as [|v' vs] "IH" forall (Φ); simplify_eq/=.
   { wp_lam. wp_match. by iApply "HΦ". }
   wp_lam. wp_match. wp_proj.
-  wp_apply ("IH" with "[//]"); iIntros "_ /=". wp_op.
+  wp_apply "IH"; iIntros "_ /=". wp_op.
   rewrite (Nat2Z.inj_add 1). by iApply "HΦ".
 Qed.
 
-Lemma lsnoc_spec xs x :
-  {{{ True }}}
-    lsnoc (val_encode xs) (val_encode x)
-  {{{ RET (val_encode (xs++[x])); True }}}.
+Lemma lsnoc_spec vs v :
+  {{{ True }}} lsnoc (llist vs) v {{{ RET (llist (vs ++ [v])); True }}}.
 Proof.
   iIntros (Φ _) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (Φ).
+  iInduction vs as [|v' vs] "IH" forall (Φ).
   { wp_rec. wp_pures. wp_lam. wp_pures. by iApply "HΦ". }
-  wp_rec.
-  wp_apply "IH"=> //.
-  iIntros (_). by wp_apply lcons_spec=> //.
+  wp_rec. wp_apply "IH"; iIntros (_). by wp_apply lcons_spec=> //.
 Qed.
 
-Lemma ltake_spec xs (n:Z) :
-  {{{ True }}}
-    ltake (val_encode xs) #n
-  {{{ RET val_encode (take (Z.to_nat n) xs); True }}}.
+Lemma ltake_spec vs (n : nat) :
+  {{{ True }}} ltake (llist vs) #n {{{ RET llist (take n vs); True }}}.
 Proof.
   iIntros (Φ _) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (n Φ).
-  - wp_rec. wp_pures. destruct (bool_decide (n ≤ 0)); wp_pures;
-      rewrite take_nil; by iApply "HΦ".
+  iInduction vs as [|x' vs] "IH" forall (n Φ).
   - wp_rec. wp_pures.
-    destruct (decide (n ≤ 0)).
-    + rewrite bool_decide_true=> //. wp_pures.
-      rewrite Z_to_nat_nonpos=> //.
-      rewrite firstn_O. by iApply "HΦ".
-    + rewrite bool_decide_false=> //.
-      wp_apply ("IH"); iIntros (_).
-      wp_apply (lcons_spec)=> //; iIntros (_).
-      rewrite -firstn_cons.
-      rewrite -Z2Nat.inj_succ; last lia.
-      rewrite Z.succ_pred.
-      by iApply "HΦ".
+    destruct (bool_decide (n ≤ 0)); wp_pures; rewrite take_nil; by iApply "HΦ".
+  - wp_rec; destruct n as [|n]; wp_pures; first by iApply "HΦ".
+    rewrite Nat2Z.inj_succ Z.sub_1_r Z.pred_succ.
+    wp_apply "IH"; iIntros (_).
+    wp_apply (lcons_spec with "[//]"); iIntros (_). by iApply "HΦ".
 Qed.
 
-Lemma ldrop_spec xs (n:Z) :
-  {{{ True }}}
-    ldrop (val_encode xs) #n
-  {{{ RET val_encode (drop (Z.to_nat n) xs); True }}}.
+Lemma ldrop_spec vs (n : nat) :
+  {{{ True }}} ldrop (llist vs) #n {{{ RET llist (drop n vs); True }}}.
 Proof.
   iIntros (Φ _) "HΦ".
-  iInduction xs as [|x' xs] "IH" forall (n Φ).
-  - wp_rec.
-    wp_pures. destruct (bool_decide (n ≤ 0)); wp_pures;
-      rewrite drop_nil; by iApply "HΦ".
+  iInduction vs as [|x' vs] "IH" forall (n Φ).
   - wp_rec. wp_pures.
-    destruct (decide (n ≤ 0)).
-    + rewrite bool_decide_true=> //. wp_pures.
-      rewrite Z_to_nat_nonpos=> //. rewrite drop_0.
-      by iApply "HΦ".
-    + rewrite bool_decide_false=> //.
-      wp_apply "IH"; iIntros (_).
-      rewrite -{1}(Z.succ_pred n) Z2Nat.inj_succ /= -Z.sub_1_r; last lia.
-      by iApply "HΦ".
+    destruct (bool_decide (n ≤ 0)); wp_pures; rewrite drop_nil; by iApply "HΦ".
+  - wp_rec; destruct n as [|n]; wp_pures; first by iApply "HΦ".
+    rewrite Nat2Z.inj_succ Z.sub_1_r Z.pred_succ.
+    wp_apply "IH"; iIntros (_). by iApply "HΦ".
 Qed.
 
-Lemma lsplit_at_spec xs n :
+Lemma lsplit_at_spec vs (n : nat) :
   {{{ True }}}
-    lsplit_at (val_encode (xs)) #n
-  {{{ RET val_encode (val_encode (take (Z.to_nat n) xs),
-          val_encode (drop (Z.to_nat n) xs)); True }}}.
+    lsplit_at (llist vs) #n
+  {{{ RET (llist (take n vs), llist (drop n vs)); True }}}.
 Proof.
-  iIntros (Φ _) "HΦ".
-  wp_lam.
-  wp_apply (ldrop_spec)=> //; iIntros (_).
-  wp_apply (ltake_spec)=> //; iIntros (_).
-  wp_pures.
-  by iApply "HΦ".
+  iIntros (Φ _) "HΦ". wp_lam.
+  wp_apply (ldrop_spec with "[//]"); iIntros (_).
+  wp_apply (ltake_spec with "[//]"); iIntros (_).
+  wp_pures. by iApply "HΦ".
 Qed.
 
-Lemma lsplit_spec xs :
+Lemma lsplit_spec vs :
   {{{ True }}}
-    lsplit (val_encode xs)
-  {{{ ys zs, RET (val_encode ys, val_encode zs); ⌜ ys++zs = xs ⌝ }}}.
+    lsplit (llist vs)
+  {{{ ws1 ws2, RET (llist ws1, llist ws2); ⌜ vs = ws1 ++ ws2 ⌝ }}}.
 Proof.
-  iIntros (Φ _) "HΦ".
-  wp_lam.
-  wp_apply (llength_spec)=>//; iIntros (_).
-  wp_apply (lsplit_at_spec)=>//; iIntros (_).
-  wp_pures.
-  iApply "HΦ".
-  iPureIntro.
-  apply take_drop.
+  iIntros (Φ _) "HΦ". wp_lam.
+  wp_apply (llength_spec with "[//]"); iIntros (_). wp_pures.
+  rewrite Z.quot_div_nonneg; [|lia..]. rewrite -(Z2Nat_inj_div _ 2).
+  wp_apply (lsplit_at_spec with "[//]"); iIntros (_).
+  iApply "HΦ". by rewrite take_drop.
 Qed.
 End lists.
-- 
GitLab