阅读时间约 18 分钟

「SF-LC」8 Maps

Logical Foundations - Total and Partial Maps

Posted by Hux on January 8, 2019
LF (逻辑基础) SF (软件基础) Coq 笔记

useful as env

Map == Dictionary

  • building data structure.
  • use of reflection to streamline proofs.

Two flavors of maps:

  1. total maps, return default when lookup fails
  2. partial maps, return option to indicate success/failure, using None as the default.

The Coq Standard Lib

From now on, importing from std lib. (but should not notice much difference)

From Coq Require Import Arith.Arith.
From Coq Require Import Bool.Bool.
Require Export Coq.Strings.String.
From Coq Require Import Logic.FunctionalExtensionality.
From Coq Require Import Lists.List.
Import ListNotations.

TODO: what’s the differences above? Answered in Coq Intensive:

  • Require give access but need to use qualified name
  • Import no need to use qualified name
  • Export module importing me no need to use qualified name as well

String in Coq is list of Char and Char is record of 8 Bool

Identifiers

we need a type for the keys that we use to index into our maps.

In Lists.v (Partial Maps):

Inductive id : Type := 
  | Id (n : nat).

From now on we will use the string from Coq’s std lib:

Definition eqb_string (x y : string) : bool :=
  if string_dec x y then true else false.

Check string_dec: (* ===> *)
     : forall s1 s2 : string, {s1 = s2} + {s1 <> s2}

The equality check fn for string from stdlib is string_des, which returns a sumbool type, i.e. {x=y} + {x≠y}.

which can be thought of as an “evidence-carrying boolean”. Formally, an element of sumbool is either or

  • a proof that two things are equal
  • a proof that they are unequal, together with a tag indicating which.

Some properties:

(* reflexive relation *)
Theorem eqb_string_refl : s : string, true = eqb_string s s.

(* functional extensionality *)
Theorem eqb_string_true_iff : x y : string, eqb_string x y = true  x = y.
Theorem eqb_string_false_iff : x y : string, eqb_string x y = false  x  y.

Total Maps

use functions, rather than lists of key-value pairs, to build maps. The advantage of this representation is that it offers a more extensional view of maps. 外延性

(where two maps that respond to queries in the same way will be represented as literally the same thing rather than just “equivalent” data structures. This, in turn, simplifies proofs that use maps.)

Definition total_map (A : Type) := string -> A.

(* empty take a default value *)
Definition t_empty {A : Type} (v : A) : total_map A :=
  (fun _ => v).

(* update take a key value pair *)
Definition t_update {A : Type} (m : total_map A)
                    (x : string) (v : A) (* : total_map A *) :=
  fun x' => if eqb_string x x' then v else m x'.

Where is the data stored? Closure!

My Reviews on API style of ML

Definition examplemap :=
  t_update (t_update (t_empty false) "foo" true)
           "bar" true.

since t_update is defined as so called “t-first” style. Reason/BuckleScript and OCaml stdlib uses this style as well:

let examplemap = 
  t_empty(false)
  |. t_update("foo", true)         /* fast pipe */
  |. t_update("bar", true) 
val add : key -> 'a -> 'a t -> 'a t
let examplemap = 
  Map.empty 
  |> Map.add "foo" true
  |> Map.add "bar" true

Or, In Jane Street “named-argument” style e.g. Real World OCaml

let examplemap = 
  Map.empty
  |> Map.add ~key:"foo" ~data:true
  |> Map.add ~key:"bar" ~data:true

Lightweight Meta-Programming in Coq - Notation

In Coq, we can leverage some meta programming:

Notation "'_' '!->' v" := (t_empty v)
  (at level 100, right associativity).

Notation "x '!->' v ';' m" := (t_update m x v)
  (at level 100, v at next level, right associativity).

Definition examplemap' :=
  ( "bar" !-> true;
    "foo" !-> true;
    _     !-> false
  ).

Noticed that the “Map building” is in a reversed order…

Note that we don’t need to define a find operation because it is just function application!

Example update_example2 : examplemap' "foo" = true.
Example update_example4 : examplemap' "bar" = true.
Example update_example1 : examplemap' "baz" = false. (* default *)

Partial Maps

we define partial maps on top of total maps. A partial map with elements of type A is simply a total map with elements of type option A and default element None.

Definition partial_map (A : Type) := total_map (option A).

Definition empty {A : Type} : partial_map A :=
  t_empty None.

Definition update {A : Type} (m : partial_map A)
           (x : string) (v : A) :=
  (x !-> Some v ; m).
  
Notation "x '⊢>' v ';' m" := (update m x v)
  (at level 100, v at next level, right associativity).

(** hide the empty case. Since it's always [None] **)
Notation "x '⊢>' v" := (update empty x v)
  (at level 100).
  
(** so nice **)
Example examplepmap :=
  ("Church" > true ; 
   "Turing" > false).

we use the “standard” map operator for partial map since maps in CS are usually partial.


Maps are functions

In many branches of mathematics, the term map is used to mean a function. partial map = partial function, total map = total function.

In category theory, “map” is often used as a synonym for morphism or arrow.

In formal logic, “map” is sometimes used for a functional symbol.



Testimonials

What readers say

先看读者反馈,再直接在当前页面继续讨论。公共留言需要 Waline 服务端;配置后访客只填昵称即可发布。

这类长文如果结构清楚,我会一路读到底。这里最好的地方是把概念、公式和代码示例放在同一篇里。

L
Lin 算法读者

数据库和工程文档的风格很实用,截图、SQL 和说明都能直接拿去复盘项目。

M
Mia 工程笔记党

强化学习相关文章密度很高,但排版如果更清楚,回看体验会更好。这个新版方向是对的。

R
Ryo 深夜学习者

我更喜欢能快速扫到标签、修改时间和文章重点的首页,现在这种卡片视图会比纯列表更容易选读。

C
Chen 知识整理控

代码块只要语言标识和层级做好,技术博客的专业感会立刻上来。

A
Ava 前端同行

评论区不用社交账号强绑定会更愿意留言,尤其是这种偏学习记录的网站。

N
Noah 匿名访客

Quick Identity

Pick a preset and leave a note

留言方式:先选择一个预设身份,再在下方输入评论。当前若显示“需要配置 Waline”,说明站点还缺少可写评论后端。

当前未选择预设身份

Live Discussion Waline 配置完成后,真实评论会加载在下方,移动端和主题切换会同步处理。
WALINE
Loading comments…