Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending wrappers & introducing functors, monads, comonads, and cowrappers #80

Draft
wants to merge 40 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4fd8389
standard definitions
stefan-aws Jan 26, 2023
4ddb452
initial
stefan-aws Jan 26, 2023
3851270
skeleton
stefan-aws Jan 26, 2023
937a778
more functions
stefan-aws Jan 27, 2023
5cc5af3
skeleton
stefan-aws Jan 27, 2023
1760fb0
types, compare, equal
stefan-aws Jan 27, 2023
b9e94f2
lemmas, more functions
stefan-aws Jan 27, 2023
5629f43
notation
stefan-aws Jan 27, 2023
7e4a628
skeleton
stefan-aws Jan 27, 2023
e5692e1
notation
stefan-aws Jan 30, 2023
909c971
notation
stefan-aws Jan 30, 2023
de84025
monad laws
stefan-aws Jan 30, 2023
5caa981
skeleton
stefan-aws Jan 30, 2023
d551c5a
Skeleton
stefan-aws Jan 30, 2023
2924847
more lemmas, quantifier fix
stefan-aws Jan 30, 2023
5886e98
more lemmas, notation
stefan-aws Jan 30, 2023
8f94e14
additional lemmas, notation
stefan-aws Jan 30, 2023
8056018
more lemmas, notation
stefan-aws Jan 30, 2023
f800ad5
Merge branch 'result-monad' into option-monad
stefan-aws Jan 31, 2023
214a185
Merge branch 'writer_monad' into option-monad
stefan-aws Jan 31, 2023
3ba2a4e
Merge branch 'reader-monad' into option-monad
stefan-aws Jan 31, 2023
614b43c
Merge branch 'either-wrapper' into option-monad
stefan-aws Jan 31, 2023
586c65a
Merge branch 'coreader-comonad' into option-monad
stefan-aws Jan 31, 2023
66e5b82
combine
stefan-aws Feb 2, 2023
7c3f145
equality
stefan-aws Feb 2, 2023
073683f
proof
stefan-aws Feb 2, 2023
d8b0a25
structure
stefan-aws Feb 3, 2023
a393e7c
delete files
stefan-aws Feb 3, 2023
a04b9f6
notation
stefan-aws Feb 3, 2023
e734bd8
doc
stefan-aws Feb 3, 2023
fbe9872
remove dll
stefan-aws Feb 3, 2023
6b125b4
remove files
stefan-aws Feb 3, 2023
2b02a33
equality
stefan-aws Feb 3, 2023
4c6fe11
resolve import of modules
stefan-aws Feb 6, 2023
00f53cf
cowrappers module
stefan-aws Feb 6, 2023
66431ea
Merge branch 'master' into option-monad
stefan-aws Feb 6, 2023
566bbae
resolve import
stefan-aws Feb 6, 2023
b237a3d
Merge branch 'option-monad' of https://github.com/dafny-lang/librarie…
stefan-aws Feb 6, 2023
5ab5399
newline, open module
stefan-aws Feb 6, 2023
29b1d90
move functions into datatype
stefan-aws Feb 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
5 changes: 4 additions & 1 deletion examples/Wrappers.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ include "../src/Wrappers.dfy"

module Demo {
import opened Wrappers
import opened Wrappers.Option
import opened Wrappers.Result
import opened Wrappers.Outcome

// ------ Demo for Option ----------------------------
// We use Option when we don't need to pass around a reason for the failure,
Expand Down Expand Up @@ -60,7 +63,7 @@ module Demo {
// Sometimes we want to go from Option to Result:
method FindName(m: MyMap<string, string>) returns (res: Result<string, string>) {
// Will return a default error message in case of None:
res := m.Get("name").ToResult();
res := ToResult(m.Get("name"));
// We can also match on the option to write a custom error:
match m.Get("name")
case Some(n) => res := Success(n);
Expand Down
2 changes: 1 addition & 1 deletion src/Collections/Arrays/BinarySearch.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ include "../../Wrappers.dfy"
include "../../Relations.dfy"

module BinarySearch {
import opened Wrappers
import opened Wrappers.Option
import opened Relations

method BinarySearch<T>(a: array<T>, key: T, less: (T, T) -> bool) returns (r: Option<nat>)
Expand Down
2 changes: 1 addition & 1 deletion src/Collections/Maps/Imaps.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
include "../../Wrappers.dfy"

module {:options "-functionSyntax:4"} Imaps {
import opened Wrappers
import opened Wrappers.Option

function Get<X, Y>(m: imap<X, Y>, x: X): Option<Y>
{
Expand Down
2 changes: 1 addition & 1 deletion src/Collections/Maps/Maps.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
include "../../Wrappers.dfy"

module {:options "-functionSyntax:4"} Maps {
import opened Wrappers
import opened Wrappers.Option

function Get<X, Y>(m: map<X, Y>, x: X): Option<Y>
{
Expand Down
5 changes: 3 additions & 2 deletions src/Collections/Sequences/Seq.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ include "../../Relations.dfy"

module {:options "-functionSyntax:4"} Seq {

import opened Wrappers
import opened Wrappers.Option
import opened Wrappers.Result
import opened MergeSort
import opened Relations
import Math
Expand Down Expand Up @@ -613,7 +614,7 @@ module {:options "-functionSyntax:4"} Seq {
/* Applies a function to every element of a sequence, returning a Result value (which is a
failure-compatible type). Returns either a failure, or, if successful at every element,
the transformed sequence. */
function {:opaque} MapWithResult<T, R, E>(f: (T ~> Result<R,E>), xs: seq<T>): (result: Result<seq<R>, E>)
function {:opaque} MapWithResult<T, R(!new), E(!new)>(f: (T ~> Result<R,E>), xs: seq<T>): (result: Result<seq<R>, E>)
requires forall i :: 0 <= i < |xs| ==> f.requires(xs[i])
ensures result.Success? ==>
&& |result.value| == |xs|
Expand Down
172 changes: 172 additions & 0 deletions src/Comonad.dfy
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// RUN: %dafny /compile:0 "%s"

/*******************************************************************************
* Copyright by the contributors to the Dafny Project
* SPDX-License-Identifier: MIT
*******************************************************************************/

include "Functor.dfy"
include "Cowrappers.dfy"

abstract module {:options "-functionSyntax:4"} Comonad refines Functor {
/* Structure */
type F(!new)<T(!new)>

function Extract<T(!new)>(w: F<T>): T

function Duplicate<T(!new)>(w: F<T>): F<F<T>>

/* Naturality */
lemma LemmaExtractNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>)
requires EquivalenceRelation(eq)
ensures eq(f(Extract(w)), Extract(Map(f)(w)))

lemma LemmaDuplicateNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>)
requires EquivalenceRelation(eq)
ensures EquivalenceRelation(Equal(eq))
ensures Equal(Equal(eq))(Duplicate(Map(f)(w)), Map(Map(f))(Duplicate(w)))

/* Counitality and Coassociativity */
lemma LemmaCoUnitalityExtract<T(!new)>(eq: (T, T) -> bool, w: F<T>)
requires EquivalenceRelation(eq)
ensures && Equal(eq)(Map(Extract)(Duplicate(w)), w)
&& Equal(eq)(w, Extract(Duplicate(w)))

lemma LemmaCoAssociativityDuplicate<T(!new)>(eq: (T, T) -> bool, w: F<T>)
requires && EquivalenceRelation(eq)
&& EquivalenceRelation(Equal(eq))
&& EquivalenceRelation(Equal(Equal(eq)))
ensures Equal(Equal(Equal(eq)))(Map(Duplicate)(Duplicate(w)), Duplicate(Duplicate(w)))
}

abstract module {:options "-functionSyntax:4"} CoreaderRightComonad refines Comonad {
import Cowrappers.Coreader

type X(!new)

function eql(x: X, y: X): bool

lemma LemmaEquiv()
ensures EquivalenceRelation(eql)

/* Functor structure */
type F(!new)<T(!new)> = Coreader.Coreader<X,T>

function Map<S(!new),T(!new)>(f: S -> T): F<S> -> F<T> {
Coreader.MapRight(f)
}

ghost function Equal<T(!new)>(eq: (T, T) -> bool): (F<T>, F<T>) -> bool {
Coreader.Equal(eql, eq)
}

/* Properties of Equal */
lemma LemmaEquivRelLift<T(!new)>(eq: (T, T) -> bool) {
LemmaEquiv();
}

/* Properties of Map */
lemma LemmaMapFunction<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, g: S -> T) {
LemmaEquiv();
}

lemma LemmaMapFunctorial<S(!new),T(!new),U(!new)>(eq: (U, U) -> bool, f: S -> T, g: T -> U, w: F<S>) {
LemmaEquiv();
}

lemma LemmaMapIdentity<T(!new)>(eq: (T, T) -> bool, id: T -> T) {
LemmaEquiv();
}

/* Comonad structure */
function Extract<T(!new)>(w: F<T>): T {
Coreader.ExtractRight(w)
}

function Duplicate<T(!new)>(w: F<T>): F<F<T>> {
Coreader.DuplicateLeft(w)
}

/* Naturality */
lemma LemmaExtractNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>) {
}

lemma LemmaDuplicateNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>) {
LemmaEquiv();
}

/* Counitality and Coassociativity */
lemma LemmaCoUnitalityExtract<T(!new)>(eq: (T, T) -> bool, w: F<T>) {
LemmaEquiv();
}

lemma LemmaCoAssociativityDuplicate<T(!new)>(eq: (T, T) -> bool, w: F<T>) {
LemmaEquiv();
}
}

abstract module {:options "-functionSyntax:4"} CoreaderLeftComonad refines Comonad {
import Cowrappers.Coreader

type X(!new)

function eqr(x: X, y: X): bool

lemma LemmaEquiv()
ensures EquivalenceRelation(eqr)

/* Functor structure */
type F(!new)<T(!new)> = Coreader.Coreader<T,X>

function Map<S(!new),T(!new)>(f: S -> T): F<S> -> F<T> {
Coreader.MapLeft(f)
}

ghost function Equal<T(!new)>(eq: (T, T) -> bool): (F<T>, F<T>) -> bool {
Coreader.Equal(eq, eqr)
}

/* Properties of Equal */
lemma LemmaEquivRelLift<T(!new)>(eq: (T, T) -> bool) {
LemmaEquiv();
}

/* Properties of Map */
lemma LemmaMapFunction<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, g: S -> T) {
LemmaEquiv();
}

lemma LemmaMapFunctorial<S(!new),T(!new),U(!new)>(eq: (U, U) -> bool, f: S -> T, g: T -> U, w: F<S>) {
LemmaEquiv();
}

lemma LemmaMapIdentity<T(!new)>(eq: (T, T) -> bool, id: T -> T) {
LemmaEquiv();
}

/* Comonad structure */
function Extract<T(!new)>(w: F<T>): T {
Coreader.ExtractLeft(w)
}

function Duplicate<T(!new)>(w: F<T>): F<F<T>> {
Coreader.DuplicateRight(w)
}

/* Naturality */
lemma LemmaExtractNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>) {
}

lemma LemmaDuplicateNaturality<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, w: F<S>) {
LemmaEquiv();
}

/* Counitality and Coassociativity */
lemma LemmaCoUnitalityExtract<T(!new)>(eq: (T, T) -> bool, w: F<T>) {
LemmaEquiv();
}

lemma LemmaCoAssociativityDuplicate<T(!new)>(eq: (T, T) -> bool, w: F<T>) {
LemmaEquiv();
}
}
61 changes: 61 additions & 0 deletions src/Cowrappers.dfy
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// RUN: %dafny /compile:0 "%s"

/*******************************************************************************
* Copyright by the contributors to the Dafny Project
* SPDX-License-Identifier: MIT
*******************************************************************************/

module {:options "-functionSyntax:4"} Cowrappers {
module {:options "-functionSyntax:4"} Coreader {

datatype Coreader<+S,+T> = Coreader(left: S, right: T)

function ExtractRight<S,T>(r: Coreader<S,T>): T {
r.right
}

function ExtractLeft<S,T>(r: Coreader<S,T>): S {
r.left
}

function DuplicateLeft<S,T>(r: Coreader<S,T>): Coreader<S,Coreader<S,T>> {
Coreader(r.left, r)
}

function DuplicateRight<S,T>(r: Coreader<S,T>): Coreader<Coreader<S,T>,T> {
Coreader(r, r.right)
}

function ExtendRight<S,T1,T2>(f: Coreader<S,T1> -> T2, r: Coreader<S,T1>): Coreader<S,T2> {
Coreader(r.left, f(r))
}

function ExtendLeft<S1,S2,T>(f: Coreader<S1,T> -> S2, r: Coreader<S1,T>): Coreader<S2,T> {
Coreader(f(r), r.right)
}

function MapRight<S,T1,T2>(f: T1 -> T2): Coreader<S,T1> -> Coreader<S,T2> {
(r: Coreader<S,T1>) =>
Coreader(r.left, f(r.right))
}

function MapLeft<S1,S2,T>(f: S1 -> S2): Coreader<S1,T> -> Coreader<S2,T> {
(r: Coreader<S1,T>) =>
Coreader(f(r.left), r.right)
}

function KleisliCompositionRight<S,T1,T2,T3>(f: Coreader<S,T1> -> T2, g: Coreader<S,T2> -> T3): Coreader<S,T1> -> T3 {
r => g(ExtendRight(f, r))
}

function KleisliCompositionLeft<S1,S2,S3,T>(f: Coreader<S1,T> -> S2, g: Coreader<S2,T> -> S3): Coreader<S1,T> -> S3 {
r => g(ExtendLeft(f, r))
}

ghost function Equal<S,T>(eql: (S, S) -> bool, eqr: (T, T) -> bool): (Coreader<S,T>, Coreader<S,T>) -> bool {
(r1: Coreader<S,T>, r2: Coreader<S,T>) =>
eql(r1.left, r2.left) && eqr(r1.right, r2.right)
}

}
}
4 changes: 2 additions & 2 deletions src/FileIO/FileIO.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ include "../Wrappers.dfy"
* File path symbols including . and .. are allowed.
*/
module {:options "-functionSyntax:4"} FileIO {
import opened Wrappers
import opened Wrappers.Result

export provides ReadBytesFromFile, WriteBytesToFile, Wrappers
export provides ReadBytesFromFile, WriteBytesToFile, Result

/*
* Public API
Expand Down
4 changes: 4 additions & 0 deletions src/Functions.dfy
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ module {:options "-functionSyntax:4"} Functions {
forall x1, x2 :: f(x1) == f(x2) ==> x1 == x2
}

function Composition<X,Y,Z>(f: X -> Y, g: Y -> Z): X -> Z {
x => g(f(x))
}

}
42 changes: 42 additions & 0 deletions src/Functor.dfy
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %dafny /compile:0 "%s"

/*******************************************************************************
* Copyright by the contributors to the Dafny Project
* SPDX-License-Identifier: MIT
*******************************************************************************/

include "Functions.dfy"
include "Relations.dfy"

abstract module {:options "-functionSyntax:4"} Functor {
import opened Functions
import opened Relations

/* Structure */
type F(!new)<T(!new)>

function Map<S(!new),T(!new)>(f: S -> T): F<S> -> F<T>

ghost function Equal<T(!new)>(eq: (T, T) -> bool): (F<T>, F<T>) -> bool
requires EquivalenceRelation(eq)

/* Properties of Equal */
lemma LemmaEquivRelLift<T(!new)>(eq: (T, T) -> bool)
requires EquivalenceRelation(eq)
ensures EquivalenceRelation(Equal(eq))

/* Properties of Map */
lemma LemmaMapFunction<S(!new),T(!new)>(eq: (T, T) -> bool, f: S -> T, g: S -> T)
requires EquivalenceRelation(eq)
requires forall x: S :: eq(f(x), g(x))
ensures forall w: F<S> :: Equal(eq)(Map(f)(w), Map(g)(w))

lemma LemmaMapFunctorial<S(!new),T(!new),U(!new)>(eq: (U, U) -> bool, f: S -> T, g: T -> U, w: F<S>)
requires EquivalenceRelation(eq)
ensures Equal(eq)(Map(Composition(f, g))(w), Composition(Map(f), Map(g))(w))

lemma LemmaMapIdentity<T(!new)>(eq: (T, T) -> bool, id: T -> T)
requires EquivalenceRelation(eq)
requires forall x: T :: eq(id(x), x)
ensures forall w: F<T> :: Equal(eq)(Map(id)(w), w)
}
Loading